1) Concept framing (short)


2) Canonical data model (portable)

PostgreSQL DDL

-- Schema versioning (simple + effective)
create table if not exists tdd_schema_version (
  id            bigserial primary key,
  version       int not null unique,
  applied_at    timestamptz not null default now()
);

-- Entities (one per screen/form)
create table if not exists tdd_entity (
  id            bigserial primary key,
  entity_key    text not null unique,   -- e.g. "customer"
  display_name  text not null,
  table_name    text not null,          -- physical table target, allow-listed by code if needed
  created_at    timestamptz not null default now(),
  updated_at    timestamptz not null default now()
);

-- Fields on a form (metadata-driven form layout)
create table if not exists tdd_field (
  id            bigserial primary key,
  entity_id     bigint not null references tdd_entity(id) on delete cascade,
  field_key     text not null,          -- e.g. "email"
  column_name   text not null,          -- e.g. "email"
  field_type    text not null,          -- allow-list: text,int,decimal,date,bool
  label         text not null,
  help_text     text null,
  is_required   boolean not null default false,
  sort_order    int not null default 0,

  -- override dimensions
  env           text null,              -- e.g. "dev","prod"
  tenant_id     text null,              -- e.g. "acme"

  -- conflict resolution
  priority      int not null default 0, -- higher wins within same specificity

  created_at    timestamptz not null default now(),
  updated_at    timestamptz not null default now(),

  unique (entity_id, field_key, env, tenant_id)
);

create index if not exists ix_tdd_field_entity on tdd_field(entity_id);
create index if not exists ix_tdd_field_lookup on tdd_field(entity_id, field_key);

-- Validations are separate rows (more flexible than columns)
create table if not exists tdd_validation (
  id            bigserial primary key,
  entity_id     bigint not null references tdd_entity(id) on delete cascade,
  field_key     text not null,
  rule_op       text not null,          -- allow-list: required,regex,min,max,min_len,max_len
  rule_arg      text null,              -- e.g. regex pattern, numeric threshold
  message       text not null,

  env           text null,
  tenant_id     text null,
  priority      int not null default 0,

  created_at    timestamptz not null default now(),
  updated_at    timestamptz not null default now()
);

create index if not exists ix_tdd_val_entity_field on tdd_validation(entity_id, field_key);

-- Permissions (role → allowed operations)
create table if not exists tdd_permission (
  id            bigserial primary key,
  entity_id     bigint not null references tdd_entity(id) on delete cascade,
  role_key      text not null,          -- e.g. "clerk","admin"
  can_view      boolean not null default true,
  can_create    boolean not null default false,
  can_edit      boolean not null default false,
  can_delete    boolean not null default false,

  env           text null,
  tenant_id     text null,
  priority      int not null default 0,

  created_at    timestamptz not null default now(),
  updated_at    timestamptz not null default now(),

  unique (entity_id, role_key, env, tenant_id)
);

create index if not exists ix_tdd_perm_entity_role on tdd_permission(entity_id, role_key);

SQLite DDL


3) Runtime algorithm

  1. Load config
  2. Conflict resolution (overrides)
  3. Validate config
  4. Failure modes
  5. Migration strategy

4) Cross-language implementation (repeat for each language)