305 lines
12 KiB
MySQL
305 lines
12 KiB
MySQL
|
|
-- Enable UUID extension
|
||
|
|
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
|
||
|
|
|
||
|
|
-- =============================================
|
||
|
|
-- MIGRATION 1: Initial Schema
|
||
|
|
-- =============================================
|
||
|
|
|
||
|
|
-- Applicants table
|
||
|
|
CREATE TABLE IF NOT EXISTS applicants (
|
||
|
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||
|
|
digilocker_id VARCHAR(255) NOT NULL UNIQUE,
|
||
|
|
name VARCHAR(255) NOT NULL,
|
||
|
|
email VARCHAR(255) NOT NULL,
|
||
|
|
phone VARCHAR(20),
|
||
|
|
wallet_address VARCHAR(42),
|
||
|
|
is_active BOOLEAN NOT NULL DEFAULT true,
|
||
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
|
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||
|
|
);
|
||
|
|
CREATE INDEX IF NOT EXISTS idx_applicant_digilocker ON applicants(digilocker_id);
|
||
|
|
CREATE INDEX IF NOT EXISTS idx_applicant_email ON applicants(email);
|
||
|
|
|
||
|
|
-- Departments table
|
||
|
|
CREATE TABLE IF NOT EXISTS departments (
|
||
|
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||
|
|
code VARCHAR(50) NOT NULL UNIQUE,
|
||
|
|
name VARCHAR(255) NOT NULL,
|
||
|
|
wallet_address VARCHAR(42) UNIQUE,
|
||
|
|
api_key_hash VARCHAR(255),
|
||
|
|
api_secret_hash VARCHAR(255),
|
||
|
|
webhook_url VARCHAR(500),
|
||
|
|
webhook_secret_hash VARCHAR(255),
|
||
|
|
is_active BOOLEAN NOT NULL DEFAULT true,
|
||
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
|
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
|
|
description TEXT,
|
||
|
|
contact_email VARCHAR(255),
|
||
|
|
contact_phone VARCHAR(20),
|
||
|
|
last_webhook_at TIMESTAMP
|
||
|
|
);
|
||
|
|
CREATE INDEX IF NOT EXISTS idx_department_code ON departments(code);
|
||
|
|
CREATE INDEX IF NOT EXISTS idx_department_active ON departments(is_active);
|
||
|
|
|
||
|
|
-- Workflows table
|
||
|
|
CREATE TABLE IF NOT EXISTS workflows (
|
||
|
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||
|
|
workflow_type VARCHAR(100) NOT NULL UNIQUE,
|
||
|
|
name VARCHAR(255) NOT NULL,
|
||
|
|
description TEXT,
|
||
|
|
version INTEGER NOT NULL DEFAULT 1,
|
||
|
|
definition JSONB NOT NULL,
|
||
|
|
is_active BOOLEAN NOT NULL DEFAULT true,
|
||
|
|
created_by UUID,
|
||
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
|
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||
|
|
);
|
||
|
|
CREATE INDEX IF NOT EXISTS idx_workflow_type ON workflows(workflow_type);
|
||
|
|
CREATE INDEX IF NOT EXISTS idx_workflow_active ON workflows(is_active);
|
||
|
|
|
||
|
|
-- License Requests table
|
||
|
|
CREATE TABLE IF NOT EXISTS license_requests (
|
||
|
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||
|
|
request_number VARCHAR(50) NOT NULL UNIQUE,
|
||
|
|
token_id BIGINT,
|
||
|
|
applicant_id UUID NOT NULL REFERENCES applicants(id) ON DELETE CASCADE,
|
||
|
|
request_type VARCHAR(100) NOT NULL,
|
||
|
|
workflow_id UUID REFERENCES workflows(id) ON DELETE SET NULL,
|
||
|
|
status VARCHAR(50) NOT NULL DEFAULT 'DRAFT',
|
||
|
|
metadata JSONB,
|
||
|
|
current_stage_id VARCHAR(100),
|
||
|
|
blockchain_tx_hash VARCHAR(66),
|
||
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
|
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
|
|
submitted_at TIMESTAMP,
|
||
|
|
approved_at TIMESTAMP
|
||
|
|
);
|
||
|
|
CREATE INDEX IF NOT EXISTS idx_request_number ON license_requests(request_number);
|
||
|
|
CREATE INDEX IF NOT EXISTS idx_request_applicant ON license_requests(applicant_id);
|
||
|
|
CREATE INDEX IF NOT EXISTS idx_request_status ON license_requests(status);
|
||
|
|
CREATE INDEX IF NOT EXISTS idx_request_type ON license_requests(request_type);
|
||
|
|
CREATE INDEX IF NOT EXISTS idx_request_created ON license_requests(created_at);
|
||
|
|
CREATE INDEX IF NOT EXISTS idx_request_status_type ON license_requests(status, request_type);
|
||
|
|
|
||
|
|
-- Documents table
|
||
|
|
CREATE TABLE IF NOT EXISTS documents (
|
||
|
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||
|
|
request_id UUID NOT NULL REFERENCES license_requests(id) ON DELETE CASCADE,
|
||
|
|
doc_type VARCHAR(100) NOT NULL,
|
||
|
|
original_filename VARCHAR(255) NOT NULL,
|
||
|
|
current_version INTEGER NOT NULL DEFAULT 1,
|
||
|
|
current_hash VARCHAR(66) NOT NULL,
|
||
|
|
minio_bucket VARCHAR(100) NOT NULL,
|
||
|
|
is_active BOOLEAN NOT NULL DEFAULT true,
|
||
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
|
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||
|
|
);
|
||
|
|
CREATE INDEX IF NOT EXISTS idx_document_request ON documents(request_id);
|
||
|
|
CREATE INDEX IF NOT EXISTS idx_document_type ON documents(doc_type);
|
||
|
|
|
||
|
|
-- Document Versions table
|
||
|
|
CREATE TABLE IF NOT EXISTS document_versions (
|
||
|
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||
|
|
document_id UUID NOT NULL REFERENCES documents(id) ON DELETE CASCADE,
|
||
|
|
version INTEGER NOT NULL,
|
||
|
|
hash VARCHAR(66) NOT NULL,
|
||
|
|
minio_path VARCHAR(500) NOT NULL,
|
||
|
|
file_size BIGINT NOT NULL,
|
||
|
|
mime_type VARCHAR(100) NOT NULL,
|
||
|
|
uploaded_by UUID NOT NULL,
|
||
|
|
blockchain_tx_hash VARCHAR(66),
|
||
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
|
|
UNIQUE(document_id, version)
|
||
|
|
);
|
||
|
|
CREATE INDEX IF NOT EXISTS idx_docversion_document ON document_versions(document_id);
|
||
|
|
|
||
|
|
-- Approvals table
|
||
|
|
CREATE TABLE IF NOT EXISTS approvals (
|
||
|
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||
|
|
request_id UUID NOT NULL REFERENCES license_requests(id) ON DELETE CASCADE,
|
||
|
|
department_id UUID NOT NULL REFERENCES departments(id) ON DELETE CASCADE,
|
||
|
|
status VARCHAR(50) NOT NULL DEFAULT 'PENDING',
|
||
|
|
remarks TEXT,
|
||
|
|
remarks_hash VARCHAR(66),
|
||
|
|
reviewed_documents JSONB,
|
||
|
|
blockchain_tx_hash VARCHAR(66),
|
||
|
|
is_active BOOLEAN NOT NULL DEFAULT true,
|
||
|
|
invalidated_at TIMESTAMP,
|
||
|
|
invalidation_reason VARCHAR(255),
|
||
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
|
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||
|
|
);
|
||
|
|
CREATE INDEX IF NOT EXISTS idx_approval_request ON approvals(request_id);
|
||
|
|
CREATE INDEX IF NOT EXISTS idx_approval_department ON approvals(department_id);
|
||
|
|
CREATE INDEX IF NOT EXISTS idx_approval_status ON approvals(status);
|
||
|
|
CREATE INDEX IF NOT EXISTS idx_approval_request_dept ON approvals(request_id, department_id);
|
||
|
|
|
||
|
|
-- Workflow States table
|
||
|
|
CREATE TABLE IF NOT EXISTS workflow_states (
|
||
|
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||
|
|
request_id UUID NOT NULL UNIQUE REFERENCES license_requests(id) ON DELETE CASCADE,
|
||
|
|
current_stage_id VARCHAR(100) NOT NULL,
|
||
|
|
completed_stages JSONB NOT NULL DEFAULT '[]',
|
||
|
|
pending_approvals JSONB NOT NULL DEFAULT '[]',
|
||
|
|
execution_log JSONB NOT NULL DEFAULT '[]',
|
||
|
|
stage_started_at TIMESTAMP,
|
||
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
|
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||
|
|
);
|
||
|
|
CREATE INDEX IF NOT EXISTS idx_wfstate_request ON workflow_states(request_id);
|
||
|
|
|
||
|
|
-- Webhooks table
|
||
|
|
CREATE TABLE IF NOT EXISTS webhooks (
|
||
|
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||
|
|
department_id UUID NOT NULL REFERENCES departments(id) ON DELETE CASCADE,
|
||
|
|
url VARCHAR(500) NOT NULL,
|
||
|
|
events JSONB NOT NULL,
|
||
|
|
secret_hash VARCHAR(255) NOT NULL,
|
||
|
|
is_active BOOLEAN NOT NULL DEFAULT true,
|
||
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
|
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||
|
|
);
|
||
|
|
CREATE INDEX IF NOT EXISTS idx_webhook_department ON webhooks(department_id);
|
||
|
|
|
||
|
|
-- Webhook Logs table
|
||
|
|
CREATE TABLE IF NOT EXISTS webhook_logs (
|
||
|
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||
|
|
webhook_id UUID NOT NULL REFERENCES webhooks(id) ON DELETE CASCADE,
|
||
|
|
event_type VARCHAR(100) NOT NULL,
|
||
|
|
payload JSONB NOT NULL,
|
||
|
|
response_status INTEGER,
|
||
|
|
response_body TEXT,
|
||
|
|
response_time INTEGER,
|
||
|
|
retry_count INTEGER NOT NULL DEFAULT 0,
|
||
|
|
status VARCHAR(20) NOT NULL DEFAULT 'PENDING',
|
||
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||
|
|
);
|
||
|
|
CREATE INDEX IF NOT EXISTS idx_webhooklog_webhook ON webhook_logs(webhook_id);
|
||
|
|
CREATE INDEX IF NOT EXISTS idx_webhooklog_event ON webhook_logs(event_type);
|
||
|
|
CREATE INDEX IF NOT EXISTS idx_webhooklog_status ON webhook_logs(status);
|
||
|
|
CREATE INDEX IF NOT EXISTS idx_webhooklog_created ON webhook_logs(created_at);
|
||
|
|
|
||
|
|
-- Audit Logs table
|
||
|
|
CREATE TABLE IF NOT EXISTS audit_logs (
|
||
|
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||
|
|
entity_type VARCHAR(50) NOT NULL,
|
||
|
|
entity_id UUID NOT NULL,
|
||
|
|
action VARCHAR(50) NOT NULL,
|
||
|
|
actor_type VARCHAR(50) NOT NULL,
|
||
|
|
actor_id UUID,
|
||
|
|
old_value JSONB,
|
||
|
|
new_value JSONB,
|
||
|
|
ip_address VARCHAR(45),
|
||
|
|
user_agent TEXT,
|
||
|
|
correlation_id VARCHAR(100),
|
||
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||
|
|
);
|
||
|
|
CREATE INDEX IF NOT EXISTS idx_audit_entity ON audit_logs(entity_type, entity_id);
|
||
|
|
CREATE INDEX IF NOT EXISTS idx_audit_entitytype ON audit_logs(entity_type);
|
||
|
|
CREATE INDEX IF NOT EXISTS idx_audit_action ON audit_logs(action);
|
||
|
|
CREATE INDEX IF NOT EXISTS idx_audit_created ON audit_logs(created_at);
|
||
|
|
CREATE INDEX IF NOT EXISTS idx_audit_correlation ON audit_logs(correlation_id);
|
||
|
|
|
||
|
|
-- Blockchain Transactions table
|
||
|
|
CREATE TABLE IF NOT EXISTS blockchain_transactions (
|
||
|
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||
|
|
tx_hash VARCHAR(66) NOT NULL UNIQUE,
|
||
|
|
tx_type VARCHAR(50) NOT NULL,
|
||
|
|
related_entity_type VARCHAR(50) NOT NULL,
|
||
|
|
related_entity_id UUID NOT NULL,
|
||
|
|
from_address VARCHAR(42) NOT NULL,
|
||
|
|
to_address VARCHAR(42),
|
||
|
|
status VARCHAR(20) NOT NULL DEFAULT 'PENDING',
|
||
|
|
block_number BIGINT,
|
||
|
|
gas_used BIGINT,
|
||
|
|
error_message TEXT,
|
||
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
|
|
confirmed_at TIMESTAMP
|
||
|
|
);
|
||
|
|
CREATE INDEX IF NOT EXISTS idx_bctx_hash ON blockchain_transactions(tx_hash);
|
||
|
|
CREATE INDEX IF NOT EXISTS idx_bctx_type ON blockchain_transactions(tx_type);
|
||
|
|
CREATE INDEX IF NOT EXISTS idx_bctx_status ON blockchain_transactions(status);
|
||
|
|
CREATE INDEX IF NOT EXISTS idx_bctx_entity ON blockchain_transactions(related_entity_id);
|
||
|
|
CREATE INDEX IF NOT EXISTS idx_bctx_created ON blockchain_transactions(created_at);
|
||
|
|
|
||
|
|
-- =============================================
|
||
|
|
-- MIGRATION 2: Users, Wallets, Events, Logs
|
||
|
|
-- =============================================
|
||
|
|
|
||
|
|
-- Users table for email/password authentication
|
||
|
|
CREATE TABLE IF NOT EXISTS users (
|
||
|
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||
|
|
email VARCHAR(255) NOT NULL UNIQUE,
|
||
|
|
password_hash VARCHAR(255) NOT NULL,
|
||
|
|
name VARCHAR(255) NOT NULL,
|
||
|
|
role VARCHAR(20) NOT NULL CHECK (role IN ('ADMIN', 'DEPARTMENT', 'CITIZEN')),
|
||
|
|
department_id UUID REFERENCES departments(id) ON DELETE SET NULL,
|
||
|
|
wallet_address VARCHAR(42),
|
||
|
|
wallet_encrypted_key TEXT,
|
||
|
|
phone VARCHAR(20),
|
||
|
|
is_active BOOLEAN NOT NULL DEFAULT true,
|
||
|
|
last_login_at TIMESTAMP,
|
||
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
|
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||
|
|
);
|
||
|
|
CREATE INDEX IF NOT EXISTS idx_user_email ON users(email);
|
||
|
|
CREATE INDEX IF NOT EXISTS idx_user_role ON users(role);
|
||
|
|
CREATE INDEX IF NOT EXISTS idx_user_department ON users(department_id);
|
||
|
|
CREATE INDEX IF NOT EXISTS idx_user_active ON users(is_active);
|
||
|
|
|
||
|
|
-- Wallets table for storing encrypted private keys
|
||
|
|
CREATE TABLE IF NOT EXISTS wallets (
|
||
|
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||
|
|
address VARCHAR(42) NOT NULL UNIQUE,
|
||
|
|
encrypted_private_key TEXT NOT NULL,
|
||
|
|
owner_type VARCHAR(20) NOT NULL CHECK (owner_type IN ('USER', 'DEPARTMENT')),
|
||
|
|
owner_id UUID NOT NULL,
|
||
|
|
is_active BOOLEAN NOT NULL DEFAULT true,
|
||
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
|
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||
|
|
);
|
||
|
|
CREATE INDEX IF NOT EXISTS idx_wallet_address ON wallets(address);
|
||
|
|
CREATE INDEX IF NOT EXISTS idx_wallet_owner ON wallets(owner_type, owner_id);
|
||
|
|
|
||
|
|
-- Blockchain events table
|
||
|
|
CREATE TABLE IF NOT EXISTS blockchain_events (
|
||
|
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||
|
|
tx_hash VARCHAR(66) NOT NULL,
|
||
|
|
event_name VARCHAR(100) NOT NULL,
|
||
|
|
contract_address VARCHAR(42) NOT NULL,
|
||
|
|
block_number BIGINT NOT NULL,
|
||
|
|
log_index INTEGER NOT NULL,
|
||
|
|
args JSONB NOT NULL,
|
||
|
|
decoded_args JSONB,
|
||
|
|
related_entity_type VARCHAR(50),
|
||
|
|
related_entity_id UUID,
|
||
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
|
|
UNIQUE(tx_hash, log_index)
|
||
|
|
);
|
||
|
|
CREATE INDEX IF NOT EXISTS idx_event_tx ON blockchain_events(tx_hash);
|
||
|
|
CREATE INDEX IF NOT EXISTS idx_event_name ON blockchain_events(event_name);
|
||
|
|
CREATE INDEX IF NOT EXISTS idx_event_contract ON blockchain_events(contract_address);
|
||
|
|
CREATE INDEX IF NOT EXISTS idx_event_block ON blockchain_events(block_number);
|
||
|
|
CREATE INDEX IF NOT EXISTS idx_event_created ON blockchain_events(created_at);
|
||
|
|
CREATE INDEX IF NOT EXISTS idx_event_entity ON blockchain_events(related_entity_type, related_entity_id);
|
||
|
|
|
||
|
|
-- Application logs table
|
||
|
|
CREATE TABLE IF NOT EXISTS application_logs (
|
||
|
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||
|
|
level VARCHAR(10) NOT NULL CHECK (level IN ('DEBUG', 'INFO', 'WARN', 'ERROR')),
|
||
|
|
module VARCHAR(100) NOT NULL,
|
||
|
|
message TEXT NOT NULL,
|
||
|
|
context JSONB,
|
||
|
|
stack_trace TEXT,
|
||
|
|
user_id UUID,
|
||
|
|
correlation_id VARCHAR(100),
|
||
|
|
ip_address VARCHAR(45),
|
||
|
|
user_agent TEXT,
|
||
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||
|
|
);
|
||
|
|
CREATE INDEX IF NOT EXISTS idx_applog_level ON application_logs(level);
|
||
|
|
CREATE INDEX IF NOT EXISTS idx_applog_module ON application_logs(module);
|
||
|
|
CREATE INDEX IF NOT EXISTS idx_applog_user ON application_logs(user_id);
|
||
|
|
CREATE INDEX IF NOT EXISTS idx_applog_correlation ON application_logs(correlation_id);
|
||
|
|
CREATE INDEX IF NOT EXISTS idx_applog_created ON application_logs(created_at);
|