Skip to content

Data Model

Cristiano Carvalho edited this page Sep 4, 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.

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
    datasets ||--o{ dataset_entries : contains
    dataset_entries ||--o{ test_cases : sources
    prompts ||--o{ prompt_suggestions : improves
    prompt_versions ||--o{ prompt_suggestions : sources
    prompt_versions ||--o{ prompt_suggestions : accepts
    suites ||--o{ prompt_suggestions : grounds
    providers ||--o{ prompt_suggestions : generates

    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
        string status
        datetime started_at
        datetime completed_at
        string error_summary
        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
        json metadata
        json artifacts
        string status
        string error
        datetime started_at
        datetime completed_at
        datetime inserted_at
        datetime updated_at
    }

    providers {
        id id
        string name
        string provider
        string model
        json config
        json pricing
        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
        id source_dataset_entry_id
        json variable_values
        json[] messages
        json[] assertions
        json metadata
        datetime inserted_at
        datetime updated_at
    }

    test_case_documents {
        id id
        id test_case_id
        string filename
        string content_type
        string storage_key
        string storage_backend
        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
        decimal avg_score
        decimal total_cost_usd
        integer cost_sample_count
        integer total_latency_ms
        integer latency_sample_count
        datetime inserted_at
        datetime updated_at
    }

    datasets {
        id id
        string name
        string description
        json metadata
        datetime inserted_at
        datetime updated_at
    }

    dataset_entries {
        id id
        id dataset_id
        string name
        json variable_values
        json[] messages
        json[] assertions
        json metadata
        integer position
        datetime inserted_at
        datetime updated_at
    }

    prompt_suggestions {
        id id
        id prompt_id
        id source_version_id
        id accepted_version_id
        id suite_id
        id provider_id
        string suggested_template
        string rationale
        json failure_summary
        string status
        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
field :status, Ecto.Enum, values: [:pending, :running, :completed, :partial_failure, :failed]
field :started_at, :utc_datetime
field :completed_at, :utc_datetime
field :error_summary, :string
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. The run row tracks the overall lifecycle, while the child run_results rows track provider-by-provider progress.

run_results

field :output, :string
field :input_tokens, :integer
field :output_tokens, :integer
field :latency_ms, :integer
field :cost_usd, :float
field :metadata, :map
field :artifacts, :map
field :status, Ecto.Enum, values: [:pending, :running, :completed, :error]
field :error, :string
field :started_at, :utc_datetime
field :completed_at, :utc_datetime
belongs_to :run
belongs_to :provider

Each run result captures provider-specific output plus execution metrics. In callback mode it can also persist arbitrary JSON-encodable metadata, and any missing metrics remain nil instead of forcing placeholder values. The artifacts map records normalized execution inputs, output, metrics, and bounded errors.

providers

field :name, :string
field :provider, Ecto.Enum, values: [:openai, :anthropic, :ollama, :google, :xai, :groq, :openrouter]
field :model, :string
field :config, :map
field :pricing, :map

Provider-specific settings such as temperature and token limits are stored in the config map. Optional pricing overrides can replace the built-in per-model defaults used for cost estimation.

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}
field :messages, {:array, :map}, default: []
field :metadata, :map, default: %{}
belongs_to :suite
belongs_to :source_dataset_entry, DatasetEntry
has_many :documents, TestCaseDocument

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

test_case_documents

field :filename, :string
field :content_type, :string
field :data, :binary, virtual: true
field :storage_key, :string
field :storage_backend, :string
field :size_bytes, :integer
belongs_to :test_case

Documents are attached to test cases, but the persisted row stores metadata plus the external storage location. The uploaded binary exists only during validation and handoff to Aludel.Storage.

suite_runs

field :results, {:array, :map}
field :passed, :integer
field :failed, :integer
field :avg_cost_usd, :decimal
field :avg_latency_ms, :integer
field :avg_score, :decimal
field :total_cost_usd, :decimal
field :cost_sample_count, :integer
field :total_latency_ms, :integer
field :latency_sample_count, :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. Individual result maps can include assertion result detail, per-test structured-output scores, retry metadata, and callback metadata, while the row-level avg_score summarizes structured-output quality across the run.

datasets and dataset_entries

Datasets hold reusable ordered examples. Entries can carry variable maps, multi-turn messages, assertions, and arbitrary metadata. Copying an entry into a suite sets source_dataset_entry_id; the suite keeps an independent snapshot after import.

prompt_suggestions

Prompt suggestions preserve the source prompt/version, grounding suite, generating provider, proposed template, rationale, summarized failures, and decision status. Status values are pending, accepted, and dismissed. An accepted suggestion links to the immutable prompt version it created.

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 versions and suite runs support historical comparison across providers, latency, cost, pass rates, and structured-output scores.
  • Dataset provenance and suggestion decision links keep reuse and optimization auditable.
  • Uploaded suite documents live behind a storage adapter. Development defaults to local storage, while production uses AWS S3 or Google Cloud Storage.

Query Examples

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