-
Notifications
You must be signed in to change notification settings - Fork 1
Data Model
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.
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
}
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.
field :name, :string
field :description, :string
field :tags, {:array, :string}
field :template, :string, virtual: true
belongs_to :project
has_many :versions, PromptVersionThe prompt record is the stable container. The editable prompt body lives in prompt_versions, not directly on the prompts table.
field :version, :integer
field :template, :string
field :variables, {:array, :string}
belongs_to :promptPrompt versions are immutable snapshots. Each new template revision is stored as a fresh row, preserving prompt history and enabling evolution analysis across versions.
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, RunResultA 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.
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 :providerEach 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.
field :name, :string
field :provider, Ecto.Enum, values: [:openai, :anthropic, :ollama, :google, :xai, :groq, :openrouter]
field :model, :string
field :config, :map
field :pricing, :mapProvider-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.
field :name, :string
belongs_to :prompt
belongs_to :project
has_many :test_cases, TestCase
has_many :suite_runs, SuiteRunSuites 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.
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, TestCaseDocumentSupported assertion types include contains, not_contains, regex, exact_match, json_field, and json_deep_compare.
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_caseDocuments 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.
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 :providerSuite 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 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 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.
- Structured tables preserve prompt lineage, suite history, and provider associations.
- Flexible fields such as
variable_values,assertions,results, and providerconfigare 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.
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])- Prompts
- Providers
- Runs and Execution
- Evaluation Suites
- Regex Assertions
- Metric Context
- Evaluator Execution Details
- Rubric Judges
- Judge Catalog
- Repeated Sampling
- Quality Policies
- ExUnit Evaluations
- File-Based Suites
- Evaluation Reporters
- Datasets
- Red-Team Datasets
- Generated Red-Team Cases
- Analytics and Prompt Evolution
- Exports and CI
- Documents and Storage
- Embedding and Access