nis2-agile/docs/sql/012_invites.sql
DevEnv nis2-agile 612befd66d [INVITE] Sistema inviti/licenze B2B + provisioning con invite_token
- InviteController: CRUD inviti (gen, list, show, revoke, rigenera, validate)
- Token inv_* sha256-hashed, one-shot o multi-use, canali, scadenza
- ServicesController::provision() accetta invite_token al posto di X-Provision-Secret
  Piano e durata forzati dall'invito, markUsed() chiaamto dopo provisioning riuscito
- index.php: routing /api/invites/* aggiunto (controller + action map)
- integrazioniext.html: nuovo tab "Inviti & Licenze" con flow completo, endpoints,
  esempi curl/php, guida lg231 aggiornata con sezione provisioning automatico

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-07 15:22:25 +01:00

59 lines
2.6 KiB
SQL

-- ============================================================
-- NIS2 Agile — Migration 012: Sistema Inviti / Licenze
-- Inviti a tempo per provisioning automatico da e-commerce,
-- lg231 e altri sistemi Agile partner.
-- ============================================================
USE nis2_agile_db;
CREATE TABLE IF NOT EXISTS invites (
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
-- Token (visibile al chiamante, formato: inv_XXXX...)
token_prefix VARCHAR(16) NOT NULL, -- es: inv_a1b2c3
token_hash VARCHAR(64) NOT NULL UNIQUE, -- SHA-256 del token completo
-- Configurazione licenza
plan ENUM('essentials','professional','enterprise') NOT NULL DEFAULT 'professional',
duration_months TINYINT UNSIGNED NOT NULL DEFAULT 12,
label VARCHAR(255) NULL, -- es: "lg231 Partner Q1 2026"
notes TEXT NULL,
-- Limiti utilizzo
max_uses TINYINT UNSIGNED NOT NULL DEFAULT 1, -- 1 = one-shot, N = multi-use
used_count TINYINT UNSIGNED NOT NULL DEFAULT 0,
-- Scadenza invito (indipendente dalla scadenza licenza)
expires_at DATETIME NOT NULL,
-- Canale di distribuzione
channel VARCHAR(64) NULL, -- 'lg231', 'ecommerce', 'direct', 'manual'
issued_to VARCHAR(255) NULL, -- email o nome destinatario
issued_by INT UNSIGNED NULL, -- user_id NIS2 admin che ha generato
-- Utilizzo
status ENUM('pending','used','expired','revoked') NOT NULL DEFAULT 'pending',
used_at DATETIME NULL,
used_by_org_id INT UNSIGNED NULL, -- org creata dall'invito
used_by_ip VARCHAR(45) NULL,
-- Restrizioni facoltative
restrict_vat VARCHAR(11) NULL, -- solo per questa P.IVA
restrict_email VARCHAR(255) NULL, -- solo per questo admin email
-- Metadata extra (JSON)
metadata JSON NULL, -- dati extra (es: lg231 order_id)
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id),
INDEX idx_invites_token_hash (token_hash),
INDEX idx_invites_status (status),
INDEX idx_invites_channel (channel),
INDEX idx_invites_expires (expires_at),
INDEX idx_invites_org (used_by_org_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
SELECT 'Migration 012 invites completata.' AS stato;