Skip to content

Data Model

Cristiano Carvalho edited this page Apr 3, 2026 · 11 revisions

Aludel stores prompts, executions, evaluations, projects, and provider configuration in PostgreSQL. The relational shape stays explicit where lineage and consistency matter, while JSON-like payloads remain flexible for assertions, variable values, and run output.

image

Schema Diagram

erDiagram
    projects ||--o{ prompts : groups
    projects ||--o{ suites : groups
    prompts ||--o{ prompt_versions : snapshots
    prompt_versions ||--o{ runs : executes
    runs ||--o{ run_results : produces
    prompts ||--o{ suites : validates
    suites ||--o{ test_cases : includes
    test_cases ||--o{ test_case_documents : attaches
    suites ||--o{ suite_runs : records
    prompt_versions ||--o{ suite_runs : evaluates
    providers ||--o{ run_results : powers
    providers ||--o{ suite_runs : evaluates_with

    projects {
        id id
        string name
        string type
        datetime inserted_at
        datetime updated_at
    }

    prompts {
        id id
        string name
        string description
        string[] tags
        id project_id
        datetime inserted_at
        datetime updated_at
    }

    prompt_versions {
        id id
        id prompt_id
        integer version
        string template
        string[] variables
        datetime inserted_at
    }

    runs {
        id id
        id prompt_version_id
        string name
        json variable_values
        datetime inserted_at
        datetime updated_at
    }

    run_results {
        id id
        id run_id
        id provider_id
        string output
        integer input_tokens
        integer output_tokens
        integer latency_ms
        float cost_usd
        string status
        string error
        datetime inserted_at
        datetime updated_at
    }

    providers {
        id id
        string name
        string provider
        string model
        json config
        datetime inserted_at
        datetime updated_at
    }

    suites {
        id id
        string name
        id prompt_id
        id project_id
        datetime inserted_at
        datetime updated_at
    }

    test_cases {
        id id
        id suite_id
        json variable_values
        json assertions
        datetime inserted_at
        datetime updated_at
    }

    test_case_documents {
        id id
        id test_case_id
        string filename
        string content_type
        binary data
        integer size_bytes
        datetime inserted_at
        datetime updated_at
    }

    suite_runs {
        id id
        id suite_id
        id prompt_version_id
        id provider_id
        json[] results
        integer passed
        integer failed
        decimal avg_cost_usd
        integer avg_latency_ms
        datetime inserted_at
        datetime updated_at
    }
Loading

Core Entities

projects

field :name, :string
field :type, Ecto.Enum, values: [:prompt, :suite]

Projects are typed containers. Prompt pages create and show :prompt projects. Suite pages create and show :suite projects. Both prompt and suite project_id references are optional, and deleting a project nilifies those references rather than cascading deletion.

prompts

field :name, :string
field :description, :string
field :tags, {:array, :string}
field :template, :string, virtual: true
belongs_to :project
has_many :versions, PromptVersion

The prompt record is the stable container. The editable prompt body lives in prompt_versions, not directly on the prompts table.

prompt_versions

field :version, :integer
field :template, :string
field :variables, {:array, :string}
belongs_to :prompt

Prompt versions are immutable snapshots. Each new template revision is stored as a fresh row, preserving prompt history and enabling evolution analysis across versions.

runs

field :name, :string
field :variable_values, :map
belongs_to :prompt_version
has_many :run_results, RunResult

A run executes a specific prompt version with a set of variable substitutions across one or more providers.

run_results

field :output, :string
field :input_tokens, :integer
field :output_tokens, :integer
field :latency_ms, :integer
field :cost_usd, :float
field :status, Ecto.Enum, values: [:pending, :streaming, :completed, :error]
field :error, :string
belongs_to :run
belongs_to :provider

Each run result captures provider-specific output plus execution metrics.

providers

field :name, :string
field :provider, Ecto.Enum, values: [:openai, :anthropic, :ollama]
field :model, :string
field :config, :map

Provider-specific settings such as API keys, temperature, and token limits are stored in the config map.

suites

field :name, :string
belongs_to :prompt
belongs_to :project
has_many :test_cases, TestCase
has_many :suite_runs, SuiteRun

Suites validate a single prompt across many scenarios. Like prompts, they can optionally belong to a typed project, but only to a :suite project from the UI.

test_cases

field :variable_values, :map
field :assertions, {:array, :map}
belongs_to :suite
has_many :documents, TestCaseDocument

Supported assertion types include contains, not_contains, regex, exact_match, and json_field.

test_case_documents

field :filename, :string
field :content_type, :string
field :data, :binary
field :size_bytes, :integer
belongs_to :test_case

Documents are stored directly in the database and can be attached to test cases to support richer evaluation inputs.

suite_runs

field :results, {:array, :map}
field :passed, :integer
field :failed, :integer
field :avg_cost_usd, :decimal
field :avg_latency_ms, :integer
belongs_to :suite
belongs_to :prompt_version
belongs_to :provider

Suite runs record the aggregate result of executing every test case in a suite against a specific prompt version and provider.

Storage Characteristics

  • Structured tables preserve prompt lineage, suite history, and provider associations.
  • Flexible fields such as variable_values, assertions, results, and provider config are stored as map-like JSON data.
  • Prompt-related records cascade where lineage must stay consistent, while project references on prompts and suites are nilified on delete.
  • Prompt versions and suite runs support historical comparison across providers, latency, cost, and pass rates.

Query Examples

# Prompt with latest version first
Prompt
|> Repo.get!(id)
|> Repo.preload(versions: from(v in PromptVersion, order_by: [desc: v.version]))

# Run with provider results
Run
|> Repo.get!(id)
|> Repo.preload(run_results: :provider)

# Suite with prompt and test cases
Suite
|> Repo.get!(id)
|> Repo.preload([:prompt, :test_cases])

Clone this wiki locally