Summary
As a lab technician, the current aliquot/tube nomenclature is confusing. In standard lab usage, an aliquot is a single portion or division of a sample—i.e., one physical item (one tube). The app currently uses aliquot to mean a batch of tubes (one Aliquot record with quantity N that has many AliquotTube children). This issue describes the changes needed so that one aliquot = one part of a sample (one tube), and aliquot is the general term for individual items.
Current behavior
- Sample – Top-level entity (e.g. cell line, patient sample).
- Aliquot – Belongs to a Sample; has
quantity (e.g. 5); represents a batch of tubes. One Aliquot = many tubes.
- AliquotTube – Belongs to an Aliquot; has
tube_number, disposition. One physical tube.
- AliquotLocation – Stores which (aliquot, tube_number) is in which box position.
So today: creating "one aliquot" with quantity 3 creates one Aliquot and three AliquotTube rows. The UI says "New Aliquot" but we are really creating one batch and multiple tubes. Lab language would call each of those tubes an aliquot (a part of the sample).
Desired behavior
- Aliquot = one individual item (one physical tube / one part of a sample). Each tube is an aliquot.
- Sample has many aliquots; each aliquot is one trackable item (one tube).
- Batch creation can still be supported as UX: e.g. "Create 5 aliquots" creates 5 aliquot records (and optionally 5 tubes or a single batch operation), not one "aliquot" with 5 tubes.
Proposed direction
-
Model / schema
- Treat one aliquot as one physical item: either merge
Aliquot and AliquotTube so that the aliquot row is the tube, or make Aliquot 1:1 with the physical item (e.g. one Aliquot per tube, no quantity on Aliquot).
AliquotLocation would reference one aliquot (one item) per slot instead of (aliquot + tube_number).
- Decide whether to keep a separate concept for "batch" or "aliquot set" (e.g. for "create 5 aliquots from this sample") as a grouping only, not as the primary entity.
-
Forms and creation flow
AliquotForm: remove or repurpose quantity; creation creates one aliquot (one item). Optionally add "Create N aliquots" (N separate aliquots or one batch operation).
- Box assignment: assign one aliquot (one item) to one slot; no
tube_number in location if aliquot = tube.
-
Views and URLs
- Detail view: one detail page per aliquot (the single item). Current
tube_detail could become aliquot_detail (one aliquot = one tube).
sample_create?type=aliquot creates one aliquot (one item); batch creation as separate flow or parameter.
-
Templates and copy
- Replace wording that implies "aliquot = multiple tubes" (e.g. "Total Tubes", "X/Y tubes") with aliquot-centric wording (e.g. one aliquot per slot, "Stored aliquots").
tube_detail.html / tube-specific UI can be refactored to aliquot_detail where the aliquot is the single item.
-
Tests and docs
- Update tests that create aliquots with
quantity and assert on AliquotTube counts.
- Update
AGENTS.md, DATA_IMPORT.md, and any user-facing docs to use the new meaning of aliquot.
-
Import process
- The CSV/data import must be updated to match the new model. Currently it creates one
sample.aliquot per CSV row with quantity from "Number of Aliquots Total", then N sample.aliquottube rows and sample.aliquotlocation (e.g. for tube 1 only). After the change, import should create one aliquot per physical item (one aliquot per tube): e.g. one CSV row with "Number of Aliquots Total" = 5 should produce 5 aliquot records (and 5 locations if storage columns are set), not one aliquot with 5 tubes.
- Person app:
DataImportView.convert_csv_to_fixtures() in person/views.py builds fixture lists for sample.aliquot, sample.aliquottube, sample.aliquotlocation; this logic must be refactored so each imported "tube" is one aliquot (and optionally one location per aliquot). Preview counts ("X aliquots, Y tubes") should be updated to the new semantics (e.g. "X aliquots" only, or "X aliquots (Y with locations)").
- Docs:
DATA_IMPORT.md describes "Aliquots", "Tubes", and "Number of Aliquots Total"; update to describe that each row can represent one or many aliquots (one per tube), and that the CSV column indicates how many aliquot records to create per row.
- Tests:
person/tests.py (e.g. DataImportViewTest.test_convert_csv_to_fixtures_method) expects sample.aliquot, sample.aliquottube, and tube counts; update expectations to the new schema and counts.
Areas to touch (non-exhaustive)
| Area |
Notes |
sample/models/aliquot.py |
Aliquot vs AliquotTube vs AliquotLocation; 1:1 or merged model |
sample/forms.py |
AliquotForm quantity, box assignment |
sample/views/create.py |
Create one aliquot (one item); create_tubes logic |
sample/views/detail.py |
Detail by aliquot (one item); TubeDetailView → AliquotDetailView or merged |
sample/urls.py |
tube/<int:pk>/ → aliquot/<int:pk>/ or keep and repurpose |
storage (assign/location) |
Assign one aliquot per slot; no tube_number in location |
sample/signals.py |
create_tubes / create_aliquot_tubes semantics |
| Templates (detail, list, storage, home) |
"Aliquot" = one item; "tubes" wording |
person/models.py |
Activity types aliquot_created / aliquot_updated (unchanged conceptually) |
| Fixtures / migrations |
Data migration: existing Aliquot + AliquotTubes → one Aliquot per tube (or chosen strategy) |
| Import process |
person/views.py (DataImportView, convert_csv_to_fixtures): create one aliquot per tube; DATA_IMPORT.md: column semantics and wording; person/tests.py: import tests and expected fixture models/counts; person admin (if it has duplicate import logic): align with views |
Migration strategy
- Data migration: Existing
Aliquot rows with quantity > 1 need a strategy: e.g. create one Aliquot per current AliquotTube (and migrate AliquotLocation to point to the new aliquot IDs) or keep a "batch" table and make aliquots reference it. Document chosen approach in the issue or a follow-up.
Acceptance criteria
Summary
As a lab technician, the current aliquot/tube nomenclature is confusing. In standard lab usage, an aliquot is a single portion or division of a sample—i.e., one physical item (one tube). The app currently uses aliquot to mean a batch of tubes (one Aliquot record with
quantityN that has manyAliquotTubechildren). This issue describes the changes needed so that one aliquot = one part of a sample (one tube), andaliquotis the general term for individual items.Current behavior
quantity(e.g. 5); represents a batch of tubes. One Aliquot = many tubes.tube_number, disposition. One physical tube.So today: creating "one aliquot" with quantity 3 creates one Aliquot and three AliquotTube rows. The UI says "New Aliquot" but we are really creating one batch and multiple tubes. Lab language would call each of those tubes an aliquot (a part of the sample).
Desired behavior
Proposed direction
Model / schema
AliquotandAliquotTubeso that the aliquot row is the tube, or makeAliquot1:1 with the physical item (e.g. oneAliquotper tube, noquantityon Aliquot).AliquotLocationwould reference one aliquot (one item) per slot instead of (aliquot + tube_number).Forms and creation flow
AliquotForm: remove or repurposequantity; creation creates one aliquot (one item). Optionally add "Create N aliquots" (N separate aliquots or one batch operation).tube_numberin location if aliquot = tube.Views and URLs
tube_detailcould becomealiquot_detail(one aliquot = one tube).sample_create?type=aliquotcreates one aliquot (one item); batch creation as separate flow or parameter.Templates and copy
tube_detail.html/ tube-specific UI can be refactored toaliquot_detailwhere the aliquot is the single item.Tests and docs
quantityand assert onAliquotTubecounts.AGENTS.md,DATA_IMPORT.md, and any user-facing docs to use the new meaning of aliquot.Import process
sample.aliquotper CSV row withquantityfrom "Number of Aliquots Total", then Nsample.aliquottuberows andsample.aliquotlocation(e.g. for tube 1 only). After the change, import should create one aliquot per physical item (one aliquot per tube): e.g. one CSV row with "Number of Aliquots Total" = 5 should produce 5 aliquot records (and 5 locations if storage columns are set), not one aliquot with 5 tubes.DataImportView.convert_csv_to_fixtures()inperson/views.pybuilds fixture lists forsample.aliquot,sample.aliquottube,sample.aliquotlocation; this logic must be refactored so each imported "tube" is one aliquot (and optionally one location per aliquot). Preview counts ("X aliquots, Y tubes") should be updated to the new semantics (e.g. "X aliquots" only, or "X aliquots (Y with locations)").DATA_IMPORT.mddescribes "Aliquots", "Tubes", and "Number of Aliquots Total"; update to describe that each row can represent one or many aliquots (one per tube), and that the CSV column indicates how many aliquot records to create per row.person/tests.py(e.g.DataImportViewTest.test_convert_csv_to_fixtures_method) expectssample.aliquot,sample.aliquottube, and tube counts; update expectations to the new schema and counts.Areas to touch (non-exhaustive)
sample/models/aliquot.pysample/forms.pyquantity, box assignmentsample/views/create.pycreate_tubeslogicsample/views/detail.pysample/urls.pytube/<int:pk>/→aliquot/<int:pk>/or keep and repurposestorage(assign/location)sample/signals.pycreate_tubes/create_aliquot_tubessemanticsperson/models.pyaliquot_created/aliquot_updated(unchanged conceptually)person/views.py(DataImportView,convert_csv_to_fixtures): create one aliquot per tube;DATA_IMPORT.md: column semantics and wording;person/tests.py: import tests and expected fixture models/counts; person admin (if it has duplicate import logic): align with viewsMigration strategy
Aliquotrows withquantity > 1need a strategy: e.g. create one Aliquot per current AliquotTube (and migrate AliquotLocation to point to the new aliquot IDs) or keep a "batch" table and make aliquots reference it. Document chosen approach in the issue or a follow-up.Acceptance criteria
DATA_IMPORT.mdand import preview/counts use the new nomenclature; import tests pass.