Complete MVP implementation including: - PHP 8.4 backend with Front Controller pattern (80+ API endpoints) - Multi-tenant architecture with organization_id isolation - JWT authentication (HS256, 2h access + 7d refresh tokens) - 14 controllers: Auth, Organization, Assessment, Dashboard, Risk, Incident, Policy, SupplyChain, Training, Asset, Audit, Admin - AI Service integration (Anthropic Claude API) for gap analysis, risk suggestions, policy generation, incident classification - NIS2 gap analysis questionnaire (~80 questions, 10 categories) - MySQL schema (20 tables) with NIS2 Art. 21 compliance controls - NIS2 Art. 23 incident reporting workflow (24h/72h/30d) - Frontend: login, register, dashboard, assessment wizard, org setup - Docker configuration (PHP-FPM + Nginx + MySQL) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
491 lines
22 KiB
SQL
491 lines
22 KiB
SQL
-- ═══════════════════════════════════════════════════════════════════════════
|
|
-- NIS2 Agile - Schema Database Iniziale
|
|
-- Database: nis2_agile_db
|
|
-- Versione: 1.0.0
|
|
-- Data: 2026-02-17
|
|
-- ═══════════════════════════════════════════════════════════════════════════
|
|
|
|
CREATE DATABASE IF NOT EXISTS nis2_agile_db
|
|
CHARACTER SET utf8mb4
|
|
COLLATE utf8mb4_unicode_ci;
|
|
|
|
USE nis2_agile_db;
|
|
|
|
-- ═══════════════════════════════════════════════════════════════════════════
|
|
-- CORE: Organizzazioni e Utenti
|
|
-- ═══════════════════════════════════════════════════════════════════════════
|
|
|
|
CREATE TABLE organizations (
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
name VARCHAR(255) NOT NULL,
|
|
vat_number VARCHAR(20),
|
|
fiscal_code VARCHAR(16),
|
|
sector ENUM(
|
|
'energy','transport','banking','health','water','digital_infra',
|
|
'public_admin','manufacturing','postal','chemical','food',
|
|
'waste','ict_services','digital_providers','space','research','other'
|
|
) NOT NULL DEFAULT 'other',
|
|
entity_type ENUM('essential','important','not_applicable') DEFAULT 'not_applicable',
|
|
employee_count INT,
|
|
annual_turnover_eur DECIMAL(15,2),
|
|
country VARCHAR(2) DEFAULT 'IT',
|
|
city VARCHAR(100),
|
|
address VARCHAR(255),
|
|
website VARCHAR(255),
|
|
contact_email VARCHAR(255),
|
|
contact_phone VARCHAR(30),
|
|
subscription_plan ENUM('free','professional','enterprise') DEFAULT 'free',
|
|
is_active TINYINT(1) DEFAULT 1,
|
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
INDEX idx_sector (sector),
|
|
INDEX idx_entity_type (entity_type),
|
|
INDEX idx_subscription (subscription_plan)
|
|
) ENGINE=InnoDB;
|
|
|
|
CREATE TABLE users (
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
email VARCHAR(255) UNIQUE NOT NULL,
|
|
password_hash VARCHAR(255) NOT NULL,
|
|
full_name VARCHAR(255) NOT NULL,
|
|
phone VARCHAR(30),
|
|
role ENUM(
|
|
'super_admin','org_admin','compliance_manager',
|
|
'board_member','auditor','employee','consultant'
|
|
) NOT NULL DEFAULT 'employee',
|
|
preferred_language VARCHAR(5) DEFAULT 'it',
|
|
is_active TINYINT(1) DEFAULT 1,
|
|
email_verified_at DATETIME,
|
|
last_login_at DATETIME,
|
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
INDEX idx_email (email),
|
|
INDEX idx_role (role),
|
|
INDEX idx_active (is_active)
|
|
) ENGINE=InnoDB;
|
|
|
|
CREATE TABLE user_organizations (
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
user_id INT NOT NULL,
|
|
organization_id INT NOT NULL,
|
|
role ENUM('org_admin','compliance_manager','board_member','auditor','employee') NOT NULL DEFAULT 'employee',
|
|
is_primary TINYINT(1) DEFAULT 0,
|
|
joined_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
|
|
FOREIGN KEY (organization_id) REFERENCES organizations(id) ON DELETE CASCADE,
|
|
UNIQUE KEY uk_user_org (user_id, organization_id),
|
|
INDEX idx_user (user_id),
|
|
INDEX idx_org (organization_id)
|
|
) ENGINE=InnoDB;
|
|
|
|
CREATE TABLE refresh_tokens (
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
user_id INT NOT NULL,
|
|
token VARCHAR(255) NOT NULL,
|
|
expires_at DATETIME NOT NULL,
|
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
|
|
INDEX idx_token (token),
|
|
INDEX idx_expires (expires_at)
|
|
) ENGINE=InnoDB;
|
|
|
|
-- ═══════════════════════════════════════════════════════════════════════════
|
|
-- GAP ANALYSIS & ASSESSMENT
|
|
-- ═══════════════════════════════════════════════════════════════════════════
|
|
|
|
CREATE TABLE assessments (
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
organization_id INT NOT NULL,
|
|
title VARCHAR(255) NOT NULL,
|
|
assessment_type ENUM('initial','periodic','post_incident') DEFAULT 'initial',
|
|
status ENUM('draft','in_progress','completed') DEFAULT 'draft',
|
|
overall_score DECIMAL(5,2),
|
|
category_scores JSON,
|
|
completed_by INT,
|
|
completed_at DATETIME,
|
|
ai_summary TEXT,
|
|
ai_recommendations JSON,
|
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
FOREIGN KEY (organization_id) REFERENCES organizations(id) ON DELETE CASCADE,
|
|
FOREIGN KEY (completed_by) REFERENCES users(id) ON DELETE SET NULL,
|
|
INDEX idx_org (organization_id),
|
|
INDEX idx_status (status)
|
|
) ENGINE=InnoDB;
|
|
|
|
CREATE TABLE assessment_responses (
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
assessment_id INT NOT NULL,
|
|
question_code VARCHAR(50) NOT NULL,
|
|
nis2_article VARCHAR(20),
|
|
iso27001_control VARCHAR(20),
|
|
category VARCHAR(100),
|
|
question_text TEXT NOT NULL,
|
|
response_value ENUM('not_implemented','partial','implemented','not_applicable'),
|
|
maturity_level TINYINT,
|
|
evidence_description TEXT,
|
|
notes TEXT,
|
|
answered_by INT,
|
|
answered_at DATETIME,
|
|
FOREIGN KEY (assessment_id) REFERENCES assessments(id) ON DELETE CASCADE,
|
|
FOREIGN KEY (answered_by) REFERENCES users(id) ON DELETE SET NULL,
|
|
INDEX idx_assessment (assessment_id),
|
|
INDEX idx_category (category),
|
|
UNIQUE KEY uk_assessment_question (assessment_id, question_code)
|
|
) ENGINE=InnoDB;
|
|
|
|
-- ═══════════════════════════════════════════════════════════════════════════
|
|
-- RISK MANAGEMENT
|
|
-- ═══════════════════════════════════════════════════════════════════════════
|
|
|
|
CREATE TABLE risks (
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
organization_id INT NOT NULL,
|
|
risk_code VARCHAR(20),
|
|
title VARCHAR(255) NOT NULL,
|
|
description TEXT,
|
|
category ENUM('cyber','operational','compliance','supply_chain','physical','human') NOT NULL,
|
|
threat_source VARCHAR(255),
|
|
vulnerability VARCHAR(255),
|
|
affected_assets JSON,
|
|
likelihood TINYINT,
|
|
impact TINYINT,
|
|
inherent_risk_score TINYINT,
|
|
treatment ENUM('mitigate','accept','transfer','avoid') DEFAULT 'mitigate',
|
|
residual_likelihood TINYINT,
|
|
residual_impact TINYINT,
|
|
residual_risk_score TINYINT,
|
|
status ENUM('identified','analyzing','treating','monitored','closed') DEFAULT 'identified',
|
|
owner_user_id INT,
|
|
review_date DATE,
|
|
nis2_article VARCHAR(20),
|
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
FOREIGN KEY (organization_id) REFERENCES organizations(id) ON DELETE CASCADE,
|
|
FOREIGN KEY (owner_user_id) REFERENCES users(id) ON DELETE SET NULL,
|
|
INDEX idx_org (organization_id),
|
|
INDEX idx_status (status),
|
|
INDEX idx_category (category),
|
|
UNIQUE KEY uk_org_risk_code (organization_id, risk_code)
|
|
) ENGINE=InnoDB;
|
|
|
|
CREATE TABLE risk_treatments (
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
risk_id INT NOT NULL,
|
|
action_description TEXT NOT NULL,
|
|
responsible_user_id INT,
|
|
due_date DATE,
|
|
status ENUM('planned','in_progress','completed','overdue') DEFAULT 'planned',
|
|
completion_date DATE,
|
|
notes TEXT,
|
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
FOREIGN KEY (risk_id) REFERENCES risks(id) ON DELETE CASCADE,
|
|
FOREIGN KEY (responsible_user_id) REFERENCES users(id) ON DELETE SET NULL,
|
|
INDEX idx_risk (risk_id),
|
|
INDEX idx_status (status)
|
|
) ENGINE=InnoDB;
|
|
|
|
-- ═══════════════════════════════════════════════════════════════════════════
|
|
-- INCIDENT MANAGEMENT (Art. 23)
|
|
-- ═══════════════════════════════════════════════════════════════════════════
|
|
|
|
CREATE TABLE incidents (
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
organization_id INT NOT NULL,
|
|
incident_code VARCHAR(20),
|
|
title VARCHAR(255) NOT NULL,
|
|
description TEXT,
|
|
classification ENUM(
|
|
'cyber_attack','data_breach','system_failure',
|
|
'human_error','natural_disaster','supply_chain','other'
|
|
) NOT NULL,
|
|
severity ENUM('low','medium','high','critical') NOT NULL,
|
|
is_significant TINYINT(1) DEFAULT 0,
|
|
status ENUM(
|
|
'detected','analyzing','containing','eradicating',
|
|
'recovering','closed','post_mortem'
|
|
) DEFAULT 'detected',
|
|
detected_at DATETIME NOT NULL,
|
|
-- NIS2 Art.23 milestones
|
|
early_warning_due DATETIME,
|
|
early_warning_sent_at DATETIME,
|
|
notification_due DATETIME,
|
|
notification_sent_at DATETIME,
|
|
final_report_due DATETIME,
|
|
final_report_sent_at DATETIME,
|
|
-- Impact
|
|
affected_services TEXT,
|
|
affected_users_count INT,
|
|
cross_border_impact TINYINT(1) DEFAULT 0,
|
|
malicious_action TINYINT(1) DEFAULT 0,
|
|
-- Resolution
|
|
root_cause TEXT,
|
|
remediation_actions TEXT,
|
|
lessons_learned TEXT,
|
|
reported_by INT,
|
|
assigned_to INT,
|
|
closed_at DATETIME,
|
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
FOREIGN KEY (organization_id) REFERENCES organizations(id) ON DELETE CASCADE,
|
|
FOREIGN KEY (reported_by) REFERENCES users(id) ON DELETE SET NULL,
|
|
FOREIGN KEY (assigned_to) REFERENCES users(id) ON DELETE SET NULL,
|
|
INDEX idx_org (organization_id),
|
|
INDEX idx_status (status),
|
|
INDEX idx_severity (severity),
|
|
UNIQUE KEY uk_org_incident_code (organization_id, incident_code)
|
|
) ENGINE=InnoDB;
|
|
|
|
CREATE TABLE incident_timeline (
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
incident_id INT NOT NULL,
|
|
event_type ENUM('detection','escalation','notification','action','update','resolution') NOT NULL,
|
|
description TEXT NOT NULL,
|
|
created_by INT,
|
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
FOREIGN KEY (incident_id) REFERENCES incidents(id) ON DELETE CASCADE,
|
|
FOREIGN KEY (created_by) REFERENCES users(id) ON DELETE SET NULL,
|
|
INDEX idx_incident (incident_id)
|
|
) ENGINE=InnoDB;
|
|
|
|
-- ═══════════════════════════════════════════════════════════════════════════
|
|
-- POLICY & PROCEDURE MANAGEMENT
|
|
-- ═══════════════════════════════════════════════════════════════════════════
|
|
|
|
CREATE TABLE policies (
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
organization_id INT NOT NULL,
|
|
title VARCHAR(255) NOT NULL,
|
|
category ENUM(
|
|
'information_security','access_control','incident_response',
|
|
'business_continuity','supply_chain','encryption','hr_security',
|
|
'asset_management','network_security','vulnerability_management'
|
|
) NOT NULL,
|
|
nis2_article VARCHAR(20),
|
|
version VARCHAR(10) DEFAULT '1.0',
|
|
status ENUM('draft','review','approved','published','archived') DEFAULT 'draft',
|
|
content LONGTEXT,
|
|
approved_by INT,
|
|
approved_at DATETIME,
|
|
next_review_date DATE,
|
|
ai_generated TINYINT(1) DEFAULT 0,
|
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
FOREIGN KEY (organization_id) REFERENCES organizations(id) ON DELETE CASCADE,
|
|
FOREIGN KEY (approved_by) REFERENCES users(id) ON DELETE SET NULL,
|
|
INDEX idx_org (organization_id),
|
|
INDEX idx_status (status),
|
|
INDEX idx_category (category)
|
|
) ENGINE=InnoDB;
|
|
|
|
-- ═══════════════════════════════════════════════════════════════════════════
|
|
-- SUPPLY CHAIN SECURITY (Art. 21.2.d)
|
|
-- ═══════════════════════════════════════════════════════════════════════════
|
|
|
|
CREATE TABLE suppliers (
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
organization_id INT NOT NULL,
|
|
name VARCHAR(255) NOT NULL,
|
|
vat_number VARCHAR(20),
|
|
contact_email VARCHAR(255),
|
|
contact_name VARCHAR(255),
|
|
service_type VARCHAR(255),
|
|
service_description TEXT,
|
|
criticality ENUM('low','medium','high','critical') DEFAULT 'medium',
|
|
risk_score TINYINT,
|
|
last_assessment_date DATE,
|
|
next_assessment_date DATE,
|
|
contract_start_date DATE,
|
|
contract_expiry_date DATE,
|
|
security_requirements_met TINYINT(1) DEFAULT 0,
|
|
assessment_responses JSON,
|
|
notes TEXT,
|
|
status ENUM('active','under_review','suspended','terminated') DEFAULT 'active',
|
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
FOREIGN KEY (organization_id) REFERENCES organizations(id) ON DELETE CASCADE,
|
|
INDEX idx_org (organization_id),
|
|
INDEX idx_criticality (criticality),
|
|
INDEX idx_status (status)
|
|
) ENGINE=InnoDB;
|
|
|
|
-- ═══════════════════════════════════════════════════════════════════════════
|
|
-- TRAINING & AWARENESS (Art. 20)
|
|
-- ═══════════════════════════════════════════════════════════════════════════
|
|
|
|
CREATE TABLE training_courses (
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
organization_id INT,
|
|
title VARCHAR(255) NOT NULL,
|
|
description TEXT,
|
|
target_role ENUM('all','board_member','compliance_manager','employee','technical') DEFAULT 'all',
|
|
nis2_article VARCHAR(20),
|
|
is_mandatory TINYINT(1) DEFAULT 0,
|
|
duration_minutes INT,
|
|
content JSON,
|
|
quiz JSON,
|
|
passing_score TINYINT DEFAULT 70,
|
|
is_active TINYINT(1) DEFAULT 1,
|
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
FOREIGN KEY (organization_id) REFERENCES organizations(id) ON DELETE CASCADE,
|
|
INDEX idx_org (organization_id),
|
|
INDEX idx_role (target_role)
|
|
) ENGINE=InnoDB;
|
|
|
|
CREATE TABLE training_assignments (
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
course_id INT NOT NULL,
|
|
user_id INT NOT NULL,
|
|
organization_id INT NOT NULL,
|
|
status ENUM('assigned','in_progress','completed','overdue') DEFAULT 'assigned',
|
|
due_date DATE,
|
|
started_at DATETIME,
|
|
completed_at DATETIME,
|
|
quiz_score TINYINT,
|
|
certificate_url VARCHAR(255),
|
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
FOREIGN KEY (course_id) REFERENCES training_courses(id) ON DELETE CASCADE,
|
|
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
|
|
FOREIGN KEY (organization_id) REFERENCES organizations(id) ON DELETE CASCADE,
|
|
INDEX idx_user (user_id),
|
|
INDEX idx_org (organization_id),
|
|
INDEX idx_status (status),
|
|
UNIQUE KEY uk_course_user (course_id, user_id)
|
|
) ENGINE=InnoDB;
|
|
|
|
-- ═══════════════════════════════════════════════════════════════════════════
|
|
-- ASSET MANAGEMENT (Art. 21.2.i)
|
|
-- ═══════════════════════════════════════════════════════════════════════════
|
|
|
|
CREATE TABLE assets (
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
organization_id INT NOT NULL,
|
|
name VARCHAR(255) NOT NULL,
|
|
asset_type ENUM('hardware','software','network','data','service','personnel','facility') NOT NULL,
|
|
category VARCHAR(100),
|
|
description TEXT,
|
|
criticality ENUM('low','medium','high','critical') DEFAULT 'medium',
|
|
owner_user_id INT,
|
|
location VARCHAR(255),
|
|
ip_address VARCHAR(45),
|
|
vendor VARCHAR(255),
|
|
version VARCHAR(50),
|
|
serial_number VARCHAR(100),
|
|
purchase_date DATE,
|
|
warranty_expiry DATE,
|
|
status ENUM('active','maintenance','decommissioned') DEFAULT 'active',
|
|
dependencies JSON,
|
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
FOREIGN KEY (organization_id) REFERENCES organizations(id) ON DELETE CASCADE,
|
|
FOREIGN KEY (owner_user_id) REFERENCES users(id) ON DELETE SET NULL,
|
|
INDEX idx_org (organization_id),
|
|
INDEX idx_type (asset_type),
|
|
INDEX idx_criticality (criticality),
|
|
INDEX idx_status (status)
|
|
) ENGINE=InnoDB;
|
|
|
|
-- ═══════════════════════════════════════════════════════════════════════════
|
|
-- AUDIT & COMPLIANCE TRACKING
|
|
-- ═══════════════════════════════════════════════════════════════════════════
|
|
|
|
CREATE TABLE compliance_controls (
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
organization_id INT NOT NULL,
|
|
control_code VARCHAR(50) NOT NULL,
|
|
framework ENUM('nis2','iso27001','both') DEFAULT 'nis2',
|
|
title VARCHAR(255) NOT NULL,
|
|
description TEXT,
|
|
status ENUM('not_started','in_progress','implemented','verified') DEFAULT 'not_started',
|
|
implementation_percentage TINYINT DEFAULT 0,
|
|
evidence_description TEXT,
|
|
responsible_user_id INT,
|
|
last_verified_at DATETIME,
|
|
next_review_date DATE,
|
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
FOREIGN KEY (organization_id) REFERENCES organizations(id) ON DELETE CASCADE,
|
|
FOREIGN KEY (responsible_user_id) REFERENCES users(id) ON DELETE SET NULL,
|
|
INDEX idx_org (organization_id),
|
|
INDEX idx_framework (framework),
|
|
INDEX idx_status (status),
|
|
UNIQUE KEY uk_org_control (organization_id, control_code)
|
|
) ENGINE=InnoDB;
|
|
|
|
CREATE TABLE evidence_files (
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
organization_id INT NOT NULL,
|
|
control_id INT,
|
|
entity_type VARCHAR(50),
|
|
entity_id INT,
|
|
file_name VARCHAR(255) NOT NULL,
|
|
file_path VARCHAR(500) NOT NULL,
|
|
file_size INT,
|
|
mime_type VARCHAR(100),
|
|
uploaded_by INT,
|
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
FOREIGN KEY (organization_id) REFERENCES organizations(id) ON DELETE CASCADE,
|
|
FOREIGN KEY (control_id) REFERENCES compliance_controls(id) ON DELETE SET NULL,
|
|
FOREIGN KEY (uploaded_by) REFERENCES users(id) ON DELETE SET NULL,
|
|
INDEX idx_org (organization_id),
|
|
INDEX idx_entity (entity_type, entity_id)
|
|
) ENGINE=InnoDB;
|
|
|
|
CREATE TABLE audit_logs (
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
user_id INT,
|
|
organization_id INT,
|
|
action VARCHAR(255) NOT NULL,
|
|
entity_type VARCHAR(100),
|
|
entity_id INT,
|
|
details JSON,
|
|
ip_address VARCHAR(45),
|
|
user_agent VARCHAR(500),
|
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
INDEX idx_user (user_id),
|
|
INDEX idx_org (organization_id),
|
|
INDEX idx_action (action),
|
|
INDEX idx_entity (entity_type, entity_id),
|
|
INDEX idx_created (created_at)
|
|
) ENGINE=InnoDB;
|
|
|
|
-- ═══════════════════════════════════════════════════════════════════════════
|
|
-- AI INTERACTIONS LOG
|
|
-- ═══════════════════════════════════════════════════════════════════════════
|
|
|
|
CREATE TABLE ai_interactions (
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
organization_id INT NOT NULL,
|
|
user_id INT NOT NULL,
|
|
interaction_type ENUM(
|
|
'gap_analysis','risk_suggestion','policy_draft',
|
|
'incident_classification','qa','report_generation'
|
|
) NOT NULL,
|
|
prompt_summary VARCHAR(500),
|
|
response_summary TEXT,
|
|
tokens_used INT,
|
|
model_used VARCHAR(50),
|
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
FOREIGN KEY (organization_id) REFERENCES organizations(id) ON DELETE CASCADE,
|
|
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
|
|
INDEX idx_org (organization_id),
|
|
INDEX idx_type (interaction_type)
|
|
) ENGINE=InnoDB;
|
|
|
|
-- ═══════════════════════════════════════════════════════════════════════════
|
|
-- RATE LIMITING
|
|
-- ═══════════════════════════════════════════════════════════════════════════
|
|
|
|
CREATE TABLE rate_limits (
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
rate_key VARCHAR(255) NOT NULL,
|
|
ip_address VARCHAR(45) NOT NULL,
|
|
attempts INT DEFAULT 1,
|
|
window_start DATETIME NOT NULL,
|
|
INDEX idx_key_ip (rate_key, ip_address),
|
|
INDEX idx_window (window_start)
|
|
) ENGINE=InnoDB;
|