Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
117 changes: 117 additions & 0 deletions migrations/20270527000000_sandbox_environment.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
-- Sandbox Environment: Data Factory, Chaos Injection, Certification Suite
-- Issue #348-sandbox

-- ── Sandbox test users (generated by Data Factory) ───────────────────────────

CREATE TABLE IF NOT EXISTS sandbox_test_users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
application_id UUID NOT NULL REFERENCES developer_applications(id) ON DELETE CASCADE,
external_id TEXT NOT NULL,
full_name TEXT NOT NULL,
email TEXT NOT NULL,
phone TEXT,
kyc_status TEXT NOT NULL DEFAULT 'verified'
CHECK (kyc_status IN ('unverified', 'pending', 'verified', 'rejected')),
balance_ngn NUMERIC(20, 4) NOT NULL DEFAULT 0,
balance_cngn NUMERIC(20, 7) NOT NULL DEFAULT 0,
stellar_address TEXT,
metadata JSONB NOT NULL DEFAULT '{}',
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);

CREATE INDEX IF NOT EXISTS idx_sandbox_test_users_app ON sandbox_test_users(application_id);
CREATE UNIQUE INDEX IF NOT EXISTS idx_sandbox_test_users_app_ext
ON sandbox_test_users(application_id, external_id);

-- ── Sandbox test bank accounts ────────────────────────────────────────────────

CREATE TABLE IF NOT EXISTS sandbox_test_bank_accounts (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
application_id UUID NOT NULL REFERENCES developer_applications(id) ON DELETE CASCADE,
test_user_id UUID REFERENCES sandbox_test_users(id) ON DELETE CASCADE,
account_number TEXT NOT NULL,
bank_code TEXT NOT NULL,
bank_name TEXT NOT NULL,
account_name TEXT NOT NULL,
currency TEXT NOT NULL DEFAULT 'NGN',
is_verified BOOLEAN NOT NULL DEFAULT TRUE,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);

CREATE INDEX IF NOT EXISTS idx_sandbox_bank_accounts_app ON sandbox_test_bank_accounts(application_id);

-- ── Sandbox mock transactions ─────────────────────────────────────────────────

CREATE TABLE IF NOT EXISTS sandbox_mock_transactions (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
application_id UUID NOT NULL REFERENCES developer_applications(id) ON DELETE CASCADE,
test_user_id UUID REFERENCES sandbox_test_users(id) ON DELETE SET NULL,
transaction_type TEXT NOT NULL CHECK (transaction_type IN ('onramp', 'offramp', 'transfer', 'mint', 'burn')),
status TEXT NOT NULL DEFAULT 'completed'
CHECK (status IN ('pending', 'completed', 'failed', 'rejected')),
amount NUMERIC(20, 4) NOT NULL,
currency TEXT NOT NULL,
stellar_tx_hash TEXT,
reference TEXT NOT NULL,
metadata JSONB NOT NULL DEFAULT '{}',
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);

CREATE INDEX IF NOT EXISTS idx_sandbox_mock_txns_app ON sandbox_mock_transactions(application_id);

-- ── Chaos scenarios ───────────────────────────────────────────────────────────

CREATE TABLE IF NOT EXISTS sandbox_chaos_scenarios (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
application_id UUID NOT NULL REFERENCES developer_applications(id) ON DELETE CASCADE,
scenario_type TEXT NOT NULL
CHECK (scenario_type IN (
'http_500', 'http_429', 'tx_rejected',
'latency_ms', 'network_timeout'
)),
-- For latency_ms: the delay in milliseconds
-- For http_429: optional retry_after header value
config JSONB NOT NULL DEFAULT '{}',
-- Which path prefix to intercept, e.g. "/api/v1/onramp"
target_path_prefix TEXT NOT NULL DEFAULT '/',
is_active BOOLEAN NOT NULL DEFAULT FALSE,
activated_at TIMESTAMPTZ,
expires_at TIMESTAMPTZ,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);

CREATE INDEX IF NOT EXISTS idx_chaos_scenarios_app_active
ON sandbox_chaos_scenarios(application_id, is_active);

-- ── Certification runs ────────────────────────────────────────────────────────

CREATE TABLE IF NOT EXISTS sandbox_certification_runs (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
application_id UUID NOT NULL REFERENCES developer_applications(id) ON DELETE CASCADE,
status TEXT NOT NULL DEFAULT 'running'
CHECK (status IN ('running', 'passed', 'failed')),
score SMALLINT, -- 0-100
passed_tests SMALLINT NOT NULL DEFAULT 0,
total_tests SMALLINT NOT NULL DEFAULT 0,
production_gate_met BOOLEAN NOT NULL DEFAULT FALSE,
started_at TIMESTAMPTZ NOT NULL DEFAULT now(),
completed_at TIMESTAMPTZ
);

CREATE INDEX IF NOT EXISTS idx_cert_runs_app ON sandbox_certification_runs(application_id);

-- ── Certification test results ────────────────────────────────────────────────

CREATE TABLE IF NOT EXISTS sandbox_certification_results (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
run_id UUID NOT NULL REFERENCES sandbox_certification_runs(id) ON DELETE CASCADE,
test_name TEXT NOT NULL,
category TEXT NOT NULL
CHECK (category IN ('deposit', 'withdrawal', 'balance', 'webhook', 'oauth', 'error_handling')),
passed BOOLEAN NOT NULL,
error_message TEXT,
duration_ms INTEGER,
executed_at TIMESTAMPTZ NOT NULL DEFAULT now()
);

CREATE INDEX IF NOT EXISTS idx_cert_results_run ON sandbox_certification_results(run_id);
Loading