Animals

An animal is the central entity. Almost everything else in the app — feedings, weighings, sales, the public profile — hangs off an animal record.

Identity

Each animal has a short code you pick (F1-23, BP-Mojo-01, whatever convention you use). The code is unique inside your space and is what shows on the QR labels for tubs and racks. You can rename it later — links and references update automatically.

The form also captures species, sex, hatch date, traits, parents (if known), maturity stage, and notes. Sex defaults to "unknown", which is fine for hatchlings — change it once you can vent or probe.

Status and state

Animals carry two independent flags, intentionally split because they answer different questions.

Status answers "is this animal in your active collection?"active or inactive.

State answers "what's its current commercial situation?"none (available), holdback, for_sale, reserved, sold, dead.

The split matters because a holdback you keep for breeding is active / holdback, while a snake you sold last year is inactive / sold. Splitting status from state means you can filter "everything I currently keep" without sales history mixing in, and you can move an animal from for_sale to holdback without recording a fictitious sale.

Available transitions

These you can do freely from the animal form:

  • noneholdbackfor_sale

These need explicit actions:

  • for_salereserved — via "Mark as Reserved" (creates a pending sale).
  • reservedfor_sale — via "Cancel Sale" on the reservation.
  • any active state → sold — via "Mark as Sold" (creates or completes the sale and clears location).
  • any active state → dead — via "Mark as Dead" (records date and cause; clears location).

Restricted states

sold and dead are locked: state and location are immutable from the form, and activities (feedings, weighings, etc.) are disabled. The form, photos, and code are still editable so you can correct typos or add a final photo. Both have one escape hatch each:

  • A sold animal reverts to for_sale if you cancel the sale (the sale row stays as history, marked cancelled).
  • A dead animal reverts via the Revive action — clears the date of death and reactivates the record. Use this only for actual mistakes; the audit log keeps the history.

The reason both are restricted: once an animal is sold or dead, the data should describe the past, not be silently rewritten. The cancel/revive escape hatches handle the "I clicked the wrong button" case without removing accountability.

Location

Every active animal lives in either a tub on a rack or a cage — never both, never neither. When you mark an animal as sold or dead, the location is automatically cleared. See Housing for the rack/tub/cage model.

Maturity

hatchling, juvenile, sub_adult, adult — set manually on the animal. The app deliberately does not auto-compute maturity from age and weight: every breeder has slow-growing lines or power-fed individuals, and the rule that fits one collection breaks another. Set it yourself when the animal hits the milestone you care about.

Traits and morph

Traits are picked from the catalog. The form distinguishes expressed traits (the animal shows the morph) from confirmed hets (carrier, hidden). The morph string at the top of the animal page — and on the public profile — is computed from those: visual traits first, hets after, in canonical order. Saved hatchlings inherit traits from the calculator's predicted offspring, including het percentages and compound decompositions like BEL = Mojave + Lesser. See Genetics for the rules.