Skip to content

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.

Vecnet — Build Spec v0.2 · Obsidian Terminal