Appearance
Operator tables
These back the Vecnet Admin operator platform. Two of them — merchants and rails — close gaps the spec referenced everywhere (entity_id, acquirer) but never defined; they are foundational and land in M1.
merchants — the BUSINESS-entity registry
Ties together accounts, fee rules, configs, and the RLS claim.
sql
create table merchants (
id uuid primary key default uuid_generate_v7(),
entity_id text not null unique, -- the entity_id used across journals/accounts/RLS
legal_name text not null,
display_name text,
type text not null default 'business', -- business | government | operator
country_code text not null default 'MX',
default_currency text not null default 'MXN',
timezone text not null default 'America/Mexico_City',
status text not null default 'onboarding', -- onboarding | active | suspended | closed
rails_enabled text[] not null default '{}', -- acquirers this merchant may use
risk_level text, -- feeds fee-rule matching
features jsonb not null default '{}', -- per-merchant feature toggles
metadata jsonb,
created_at timestamptz not null default now(),
modified_at timestamptz not null default now()
);rails — the acquirer-as-plugin registry
One row per rail. Adding a rail = a row + a Listener adapter.
sql
create table rails (
id uuid primary key default uuid_generate_v7(),
acquirer text not null unique, -- tonder | menta | ...
display_name text not null,
capture_model text not null, -- cnp (tonder) | cp (menta)
status text not null default 'active',-- active | disabled
capabilities text[] not null default '{}', -- payment, refund, dispute, withdrawal, 3ds, apm, ...
api_base_url text, -- non-secret endpoint
credentials_ref text, -- Vault reference — NEVER the secret itself
webhook_secret_ref text, -- Vault reference for inbound signature verification
config jsonb, -- rail-specific knobs
created_at timestamptz not null default now(),
modified_at timestamptz not null default now()
);webhooks + webhook_deliveries
The outbound Webhook Manager delivers against these.
sql
create table webhooks (
id uuid primary key default uuid_generate_v7(),
entity_id text not null, -- merchant, or 'V1' for platform
url text not null,
events text[] not null, -- payment.succeeded | payment.failed | settlement.confirmed | ...
secret_ref text not null, -- Vault ref for HMAC signing
status text not null default 'active',
created_at timestamptz not null default now(),
modified_at timestamptz not null default now()
);
create table webhook_deliveries (
id uuid primary key default uuid_generate_v7(),
webhook_id uuid not null references webhooks(id),
correlation_id text,
event text not null,
payload jsonb not null,
status text not null default 'pending', -- pending | delivered | failed
attempts int not null default 0,
response_code int,
next_retry_at timestamptz,
created_at timestamptz not null default now(),
delivered_at timestamptz
);
create index on webhook_deliveries (status, next_retry_at);operators + audit_log
Operator RBAC + an immutable audit of every config mutation.
sql
create table operators (
id uuid primary key default uuid_generate_v7(),
user_id uuid not null, -- Supabase Auth user
email text not null unique,
role text not null, -- vecnet_admin | finops | support | read_only
status text not null default 'active',
created_at timestamptz not null default now()
);
create table audit_log (
id uuid primary key default uuid_generate_v7(),
operator_id uuid references operators(id),
action text not null, -- created | updated | deleted | triggered
resource_type text not null, -- merchant | rail | fee_rule | webhook | settlement | config | ...
resource_id text,
before jsonb,
after jsonb,
created_at timestamptz not null default now()
);
create index on audit_log (resource_type, resource_id, created_at desc);Audit is non-negotiable
Every config mutation in the operator platform writes an audit_log row — for a surface that edits money rules. Secrets (rail credentials, webhook signing keys) live in Supabase Vault; these tables hold only references.