Kadoo -- Data Model

An exploration about how to better model Animal Welfare Data

Series Contents

  1. Kadoo, Animal Welfare Data Platform
  2. Data Model < – You are here

“Reveal unto me the secrets of your universe.”

With the basic dream-list of an animal welfare data management platform in our pocket, let’s turn our attention to what that might actually look like.

When designing systems like Kadoo, I like to start from the bottom up. I’m a data monkey. So, as we continue the daydream, we won’t decide on every type of resource, field, or data point. We would need a lot more expert input and iteration to even think about that. What I want to do here is build a skeleton onto which we can add muscle and skin.

The Shape of Data

How we organize data is more important than the actual data. The data must be well structured, predictable, and flexible. We will build this data model with some aims in mind:

  1. Express relationships well. Build a graph so that multiple resources are connected.
  2. Allow for precise querying and updating (get exactly what you want).
  3. Have multiple entry points to any relationship graph (start your search anywhere and walk the graph).
  4. Have easily shareable and expressible ids for use in busy in-person settings.
  5. Be fit for data exchange standards.

Number 5 deserves a post of its own (and I’ll get around to it). In short, the power of data is in its portability – in being able to share, consume, replicate, and understand that data no matter the source. There are many examples of industry data standards. The Real Estate Standards Organization is the standard with which I am most familiar.

As I said, I will explore this potential standards format (with current examples) later, but I wanted to keep that in mind while designing the internal data model for Kadoo.

Overview

The core components are Resources, which are all top level. So, a single Animal resource doesn’t have a field on it called “vaccinations”, but instead has a relationship to a top-level Medical resource that describes the vaccinations.

Since many kinds of resources can have different shapes (medical vaccinations, medical treatment, medical assessment), we have “types” to differentiate them. These types define what is special about each kind of the resource.

Notes are text notes that are their own top-level resource. Persons are also special top-level resources. Some of those persons also have Authentication records that let them login. Persons with authentications also have roles and permissions that define what they can see, update, and create. Remember that in Kadoo, many more people have Authentication than the typical staff/volunteers.

Relationships are the important glue that brings everything together. Animals have Behavior resources, but Behavior resources also have Animals. All the relationships are two-way so you can always find your way home again.

Last, Views are the templates through which you see the data. Since the data has many complex relationships, a single query can be provide far data than is needed. Views decide what relationships are expanded, what fields are shown, in what order things appear, and how far across the graph we walk. Views are not visual. We’re not talking about graphical views. All the data is in some exchange format like JSON. Roles and Permissions are also applied to views.

Resources and Types

The Shape of a Resource

At the core of the data model are Resources which represent some unique, important, and useful record. Some examples of resources would be:

  • Animal: The core information about a specific animal including age, species, breed, etc.
  • Medical: Any single medical treatment, exam, or procedure
  • Behavior: Any single behavior treatment, test, or intervention
  • Person: Any person (with or w/o authentication)

And many, many more. The purpose here is to outline the shape of the data, not its finer points.

Resource IDs

Each individual resource (like a specific animal or a single medical vaccination) has a unique id that is a prefix and a human readable, easily shareable id (in base36, meaning all numbers and English letters).

  • Animal: A-2JK, A-19L, A-P688KA
  • Behavior: B-Z3, B-80

I can’t tell you how many times I’ve been working in a busy area, trying to talk about some specific animal and saying a long, complicated number or trying to spell some bizarre name. To remedy this, we use ids like the above.

This base 36 scheme allows for literally billions of resources in only a few characters (6).

Core Data

You’ll notice that a single Behavior resource (for example) includes all possible behavior tests, assessments, and interventions. But a “Fearful Fido” procedure is not at all the same as an “Intake Assessment”, and what’s more, those protocols evolve with new research. We will discuss that flexibilty next, but first let’s focus on what they have in common.

All resource have some system-wide data attached to them like the id, the resource owner, and timestamps. Beyond that, each resource will have some common, core data specific to its resource. For behavior (for example) it would include the animals involved, the people involved, and a note. More on persons and notes in a bit.

So, let’s start building our example of a Behavior resource:

{
   // This ID for the Behavior Resource
   id: "B-2J3K",

   // Relationship to the Person Resource
   // The Staff Person who first created this animal record
   owner: "P-3J",

   // Relationships to the Person Resource
   // Other people who were involved
   persons: ["P-3J", "P-K2I9"],

   // Which animals were involved
   animals: ["A-9", "A-7AJK"]

   // The date the behavior resource was created
   date: "2020-01-01",

   // The location the procedure took place
   // This is a configurable list
   location: {
       site: "main-campus",
       subsite: "play-yards",
       unit: "2"
   }, 
}


Flexibility Through Types

I will start by saying I do not like the term “type” and have toyed with “instance” and “kind” but neither is quite right.

Flexibility happens thanks to “types” which do not have special ids, and are not directly exposed to the public. A “type” would be those “fearful fido tests” or “vaccination procedure”s. They specific type defines the schema that makes that individual instance of a resource unique. For example, the “vaccine procedure” type of the Medical resource would define data points for the vaccine(s) used, maker, and revaccination date.

Building onto our Behavior Resource, a type may look like:

   // This is the type of type (type of procedure) it is
   // This is configurable
   // some examples would be "Play Date", "Treatment", "Intake Assessment"
   // This data would be different for different kinds of types
   // The type of data presented is configurable. You can edit the schema.
   types: {
      play_date: {
         duration_in_minutes: 30,
         concerns: ["Barking", "Jumping", "Nipping"],
      }
   }


Notes and Persons at the Heart

Persons are (of course) people. This includes persons with authentications privilege (users like staff and volunteers) and those without. Its worth noting that in Kadoo, many more people have authentication privilege than in most systems. Because of its open nature, this includes adopters, community members, fosters, etc. Each with their own authentication, but with limited permissions.

{
    // Some core data shared by all persons
    id: "P-18X3",
    name: "Kayla Colman",
    sort-name: "Colman",
   
    // The auth data here is shown for clarity, 
    // but would not be shared through public apis.
    // This data is locked down behind permissions
    authentication: {
        login_key: "kcolman@somegreatrescue.org"
    }
}


Notes are the other core resource. Notes are anything you want to be known. Notes form the basis of timelines, reports, and all entries. Other resources have relationship with notes, but the notes are unique. We will see why in a bit.

{
    // Some core data shared by all persons
    id: "N-O7",
    owner: "P-881"
    text: "Notes with **markdown** and [redact]annotations[/redact]",
    created_at: "12-10-2024",
    updated_at: "2-1-2025",
}


Relationships

What makes data interesting are the relationships between resources. This is also one thing that makes Kadoo distinct from many other systems. A single Behavior resource can be connected to multiple people and multiple animals. There is a “primary note” attached to the behavior resource itself. And, each specific animal in the behavior session can have their own set of notes. A single Vaccine Event Resource can be attached to multiple animals and multiple persons.

For example, the behavior from above may have these notes added via relationships:

{
   id: "B-2J3K",

   // . . . All the other stuff shown above

   session_notes: "N-4CL0",

   animal_notes: {
      "A-9": "N-D10",
   },
}


In this way, all the resources build a powerful graph that can be traversed. You can explore (walk) the graph from a vaccine event to an animal to their behavior to an outcome to that adopter to the pet pantry events that adopter was a part of.

Views

So, now we have a graph of resources connected together by powerful relationships. Each of those relationships can be expanded arbitrarily. That’s a LOT of data that can be chased from a single Animal resource, for example.

In order to bring some sanity to this hurricane, let’s introduce Views as their own, special resource.

A View is exactly that: a representation of the data at hand. One view of an Animal resource may only show the ids of the behavior notes. Another would expand those ids to be an abbreviated representation of the behavior records. Yet another expands them entirely. Some views will only show certain information (no medical information, for example).

Views are also related to permissions. When an adopter views an Animal resource, they have limited permissions and are only able to see what they are permitted to see. They may start on a view (V-18L) and then have permissions applied to that view, further restricting the data they can see. In this way, they create a new view specific to only them (V-20P1).

Pulling It Together

So, let’s put that together with some examples. Let’s look at a json representation of a behavior resource.

This would be the default view with no expansions. Just using the ids to define relationships

GET /behaviors/B-2J3K

{
   // This ID for the Behavior Resource
   id: "B-2J3K",

   // Relationship to the Person Resource
   // The Staff Person who first created this animal record
   owner: "P-3J",

   // Relationships to the Person Resource
   // Other people who were involved
   persons: ["P-3J", "P-K2I9"],

   animals: ["A-9", "A-7AJK"]

   // The date of the behavior resource
   date: "2020-01-01",

   // The location the procedure took place
   // This is a configurable list
   location: {
       site: "main-campus",
       subsite: "play-yards",
       unit: "2"
   },

  
   // The Note for the behavior session itself, includes all the animals
   session_notes: "N-4CL0",

   // Any notes specific to an animal in the procedure
   animal_notes: {
      // This note is for the animal A-9, 
      // which is also referenced in the animals field
      "A-9": "N-D10",
   },

   // This is the type of type (type of procedure) it is
   // This is configurable
   // some examples would be "Play Date", "Treatment", "Intake Assessment"
   types: {
        "play_date": {
            // The data is specific to the Play Date type
            // This data would be different for different kinds of types
            // The type of data presented is configurable. You can edit the schema.
            duration_in_minutes: 30,
            concerns: ["Barking", "Jumping", "Nipping"],
        }
    }
}


And, if we wanted to see a view on that data, it may look like:

GET /behaviors/B-2J3K/V-289CL

{
    id: "B-2J3K",
    owner: {
        id: "P-3J",
        name: "Kayla Coleman"
    },
    persons: ["P-3J", "P-K2I9"],
    animals: [
        {
            id: "A-9", 
            name: "Quin"
        },
        {
            id: "A-7AJK", 
            name: "Kadoo"
        }
    ]
    date: "2020-01-01",
    session_notes: {
        id: "N-4CL0",
        text: "These are the notes for the behavior session in general"
    },
    types: {
        "play_date": {
            duration_in_minutes: 30,
            concerns: ["Barking", "Jumping", "Nipping"],
        }
    }

    // Notice that we left out location, and animal notes entirely
}


Overview Again

That was a lot. Let’s just go through the overview one more time.

  • The core components are Resources, which are all top level.
  • Resources have “core” data that is shared by all resources of that kind (Behavior, Medical, Animal, Person)
  • Resource have “types” for the specific sub-resource kind that we’re talking about (Vaccinations, Behavior Treatment, etc)
  • Notes and Persons are important resources.
  • Relationships glue everything together.
  • Views define what data is actually returned and what that return looks like.

Conclusion and Next Steps

This has been a messy (and hopefully not too confusing) exploration of what a data model for Animal Welfare Data could look like. This is not at all a complete example, but a simple discover of a system that could be used.

In any case, as I mentioned before, this is NOT a proposal or pitch or business plan. This is not a document about implementation. This is a space to dream.


Post Image Created with DALLE. Temporary logo.

Last Updated: April 8, 2024 – See Changes