Designing an environment

Walk through a real PK/PD study schema in mice.

Designing the schema for a study is the highest-leverage hour you'll spend in Dalea. A schema that captures the right entities and relationships will let you ask arbitrary analytical questions for the next decade. A schema that doesn't will leave you exporting CSVs and joining things in Pandas forever.

This page walks through the schema for a realistic mouse PK/PD study end to end.

The study

A 24-mouse single-dose PK study of a small-molecule kinase inhibitor (test article DLA-7) in C57BL/6 females. Three dose groups (3, 10, 30 mg/kg PO) plus vehicle. Plasma collected at 15 min, 1 h, 4 h, 24 h. Analyte is parent compound by LC-MS/MS.

The schema

Four entity tables and one result table:

Animalsentity tableanimal_id (PK)sexenumstrainenumbaseline_weight_gnumberstudy_group→ groupsStudy groupsentity tablegroup_id (PK)namedose_mg_per_kgnumberrouteenumtest_article→ articlesTest articlesentity tablearticle_id (PK)namemodalityenumlotPlasma samplesentity tablesample_id (PK)animal→ animalstimepoint_hnumbercollected_atdatePK resultsresult table— dimensions —animal→ animalstimepoint_hnumber— measurements —concentration_ug_mlnumberauc_0_24number
Hover a table to highlight its references. Dotted lines show reference columns; the result table splits explicitly into dimensions (the axes you query by) and measurements (the numbers you record).
Hover any table to see its outgoing references. Reference columns are dotted; result tables explicitly split into dimensions and measurements.

Step-by-step

  1. Create the environment
    Workspace → Data → New environment

    The dialog asks for three things: a name (In-vivo PK), an icon, and an optional description of what the environment is for. Everything else, tables, columns and references, is added afterwards in the designer.

  2. Add the test articles table

    The most upstream entity. Give the table the record-name pattern TA-{###}, so each row is stamped TA-001, TA-002 and so on. Columns:

    • name (text, flagged Record label)
    • modality (enum: small-molecule, mAb, ASO, peptide, mRNA…)
    • lot (text)
  3. Add the study groups table

    Bridges test article to dose level. Record-name pattern GRP-{###}.

    • name (text — "Vehicle", "DLA-7 3 mg/kg", …)
    • dose (number, unit mg/kg)
    • route (enum: PO, IV, IP, SC)
    • test_article (reference → test articles)
  4. Add the animals table

    The actual subjects. Record-name pattern ANM-{###}, giving ANM-001, ANM-002 and so on.

    • sex (enum: M, F)
    • strain (enum: C57BL/6, BALB/c, NSG…)
    • baseline_weight (number, unit g, validation: 15–35)
    • study_group (reference → study groups)

    Note the validation: weights outside 15–35 g flag during entry — almost certainly a typo for an adult mouse.

  5. Add the plasma samples table

    One row per timepoint per animal. Record-name pattern SMP-{####}.

    • animal (reference → animals)
    • timepoint (number, unit h, min 0)
    • collected_at (datetime)
  6. Add the PK results result table

    The shape is different: a result table splits into dimensions and measurements.

    • Dimensions: animal (ref), timepoint (number, unit h)
    • Measurements: concentration (number, unit ug/mL), auc_0_24 (number, unit ug.h/mL), cmax (number, unit ug/mL), tmax (number, unit h)

    Dimensions are what you'll group/filter by in queries. Measurements are the values you'll aggregate. The unit is a property of each number column (pick it in the designer, any spelling such as µg/mL is accepted), never part of the name and never a separate text column: cells, charts and query results then render it for you, and compatible input such as 0.5 mg/mL converts on entry.

Why a result table — couldn't this be one big entity table?

It could. But result tables get two things for free:

  • Batched recording. All four timepoints from one animal-day fit in one result batch, which carries a single operator, timestamp and origin.
  • Analytical aggregation. You can ask "mean concentration grouped by dose level" without writing SQL: a query rooted at the animals table hops into the result schema and collapses its measurements per group. The dimension/measurement split is what makes that possible.

Record-name patterns recap

TablePatternGenerates
Test articlesTA-{###}TA-001, TA-002, …
Study groupsGRP-{###}GRP-001, GRP-002, …
AnimalsANM-{###}ANM-001, ANM-002, …
SamplesSMP-{####}SMP-0001, SMP-0002, …

A pattern is literal text plus tokens. The tokens are {###} or {0001} for a zero-padded counter (the width is the number of characters inside the braces), {A} / {AA} for an alphabetic counter, {uuid} or {uuid:8} for a random hex fragment, and {column_name} to interpolate one of the table's own columns. There is no date token, so a year has to come from a real column, as in {collection_year}-{study}-{###}.

Patterns are set per table in the designer. The counter lives on the table and advances once per row; on project- or entry-scoped tables each scope keeps its own counter, so numbering restarts per study.

Tracking the physical stock

The schema above records what you measured. If you also need to track the vials themselves, how much is left in each and which freezer they sit in, add an inventory table to this same environment. It is a third table kind alongside entity and result tables, and it links back to a catalog table like Test Articles so eleven vials resolve to one compound.

See designing item types.

What's next