Parent-child data model

Artyc

Series A

Climate Tech

The empty state is where Group has to teach itself. Creating one names it, attaches a shipping profile, and turns the page into a table.

The empty state is where Group has to teach itself. Creating one names it, attaches a shipping profile, and turns the page into a table.

The short version

A courier in the Bay Area was running 10 shippers during a 3-month pilot for a large hospital system. Most of the fleet went out every day. To share data with someone at the hospital, it meant downloading the CSV, drafting the email, and making the CSV legible for the customer. As many as forty times a week.

The hospital hires the courier to move temperature-controlled material between its sites, so the courier owns the vehicles and the shippers while the hospital owns the reason the shipment exists. Both need the same temperature record, for different things. The courier to show it did the job, the hospital to decide whether the material can be used. The portal had no way to describe that relationship, because it was built for our customer and not for our customer's customer.

Groups is what replaced the exporting and the emailing. Most of the work was the data model and the word, co-designed with the person who had been doing it by hand.

My role was to write the requirements, the permission model, the interface specs, and the architecture memo that decided how the data was structured. Built alongside two engineers.

The person who mattered most wasn't on our team. The courier's operations lead was the one exporting and emailing, and she used every version. She'd tell me when something was worse than the spreadsheet she already had.

The hospital signs in and sees its own journeys. The courier sees the fleet. Neither can see the other.

The problem

Every courier-shaped customer hits the same wall. The deals we could close ran 10-20 shippers. The prospects behind the wall were some of the largest pharmaceutical distributors in the country, where an account opens at 50 shippers, can run past 100, and where several organizations need different slices of the same fleet. We struggled to sign those deals because our system couldn't do that well.

Underneath sat a core requirement. No organization could ever see another's data. This was not a bug to fix later. In healthcare it is the thing that ends a sale.

The role and the scope get picked together. The permissions are written out before the invite sends for added clarity. Customized permissions is on the roadmap.

The approach

Parent and child model first, nothing else. Ship it before month one of the pilot was out, prove the architecture, then widen it. We pushed to production in week four and walked the courier through it. The two months that followed went to watching them use it and making small adjustments.

What to call it

The engineering term is parent and child organizations. It's accurate. It's also a phrase nobody at a courier uses about their own clients, and the hierarchy is backwards. Parent orgs, entities, and sub-organizations were all considered and dropped for the same two reasons. They rank the hospital under the courier, or they're clunky.

A second constraint came from customers who weren't in the room. A courier is one customer type of several at Artyc. A clinical trial site would group by trial rather than by client, with its sponsor looking in. Another operator might group by region. The word had to be loose enough to hold a hospital this year and a trial or a region next year.

The user-facing word became Group.

How deep the hierarchy goes

The customer in front of us needed two levels: themselves (the courier), and the organizations it delivers for. We set the requirements at two explicitly and listed anything deeper as a future item.

The problem is who comes next. Contract research organizations run cold chain for pharma sponsors, and each sponsor runs several studies. That's three levels, and it's a large market. A prospect needing three would either be told no, or squashed into two by collapsing sponsor and study into one Group, which loses the isolation that made the feature worth having.

The schema and the interface don't have to agree. Groups gained one nullable column pointing at another Group. The application layer refuses anything deeper than two, and the interface never mentions depth at all.

The cheap insurance is to make the schema reversible by software now and the interface reversible by product later.

Excerpt from the architecture memo

One column, added before a customer asked for it, is the difference between a scoping conversation and a data migration. It cost almost nothing.

The third layer customers asked for turned out to be people, not organizations. A driver gets a record and a phone number. No added seat and nobody to onboard.

What landed

The manual loop is gone. The courier's operations lead exports nothing and emails nobody, because the hospital signs in and reads its own journeys. The pilot converted. A 40 unit purchase order at the end of the pilot. The sharing model was a big part of closing it. Since then, larger purchase orders from other couriers have landed and this data model is something they all asked for.

The courier we built it with has since been acquired by a national medical logistics network. That takes the model from one Bay Area operation to a network of subsidiaries, each with hospital clients of its own, and the same courier-and-client shape multiplied across it.

A driver gets a record and a phone number. No seat, no login, nobody to onboard.

What I’d do differently

During the pilot, the courier came back asking for a third layer, and it wasn't the one I'd hedged for.

They wanted to match drivers to specific shippers. People, not organizations. What those people didn't need mattered more than what they did: no account to onboard, no calendar, no login, no seat. Somebody the system refers to rather than somebody who uses it.

The nullable column did nothing for that. I'd bought flexibility along the axis I could picture, which was organizational depth, and the demand arrived along one I hadn't, which was entity type. A driver is not a small organization. Modeling them as one would have handed every courier a pile of empty tenants to administer, which is exactly the overhead they'd been telling us they didn't want.

The first version of field personnel shipped inside the pilot window. By the end of three months they were assigning drivers to shippers with it. The name is Field Personnel rather than drivers for the same reason the sharing model is called Group. Drivers is the courier's word. A clinical trial site has lab technicians handling shippers. Somewhere else it's a unit assigned to one named person. Same entity, different word at every customer, so the feature gets the word that belongs to none of them.

I don't think the hedge was wrong. It cost one column and it's still the right insurance against the hierarchy question. But it's a clean example of the thing I still don't have a method for. Being sure something will change is easy. Being right about which thing is a different problem, and buying flexibility everywhere is a slower way of building nothing.

The same command wherever you are. A journey joins a Group the same way a shipper does.

What’s still open

With the emailing gone, the work left is opening every journey to decide whether it mattered. So automated journey summaries are being built. An excursion narrative that gives a first read on what happened and, where the data supports it, why, with computed thermal headroom alongside. Natural-language fleet queries are moving through the command menu. The mechanics are still being prototyped, so that is as much as I'll claim for it.

Note: To respect confidentiality and regulatory compliance, interface images are built against the product's own design system and populated with fixture data. No customer records, colleague names, or partner names appear anywhere in this case.

Parent-child data model

Artyc

Series A

Climate Tech

The empty state is where Group has to teach itself. Creating one names it, attaches a shipping profile, and turns the page into a table.

The empty state is where Group has to teach itself. Creating one names it, attaches a shipping profile, and turns the page into a table.

The short version

A courier in the Bay Area was running 10 shippers during a 3-month pilot for a large hospital system. Most of the fleet went out every day. To share data with someone at the hospital, it meant downloading the CSV, drafting the email, and making the CSV legible for the customer. As many as forty times a week.

The hospital hires the courier to move temperature-controlled material between its sites, so the courier owns the vehicles and the shippers while the hospital owns the reason the shipment exists. Both need the same temperature record, for different things. The courier to show it did the job, the hospital to decide whether the material can be used. The portal had no way to describe that relationship, because it was built for our customer and not for our customer's customer.

Groups is what replaced the exporting and the emailing. Most of the work was the data model and the word, co-designed with the person who had been doing it by hand.

My role was to write the requirements, the permission model, the interface specs, and the architecture memo that decided how the data was structured. Built alongside two engineers.

The person who mattered most wasn't on our team. The courier's operations lead was the one exporting and emailing, and she used every version. She'd tell me when something was worse than the spreadsheet she already had.

The hospital signs in and sees its own journeys. The courier sees the fleet. Neither can see the other.

The problem

Every courier-shaped customer hits the same wall. The deals we could close ran 10-20 shippers. The prospects behind the wall were some of the largest pharmaceutical distributors in the country, where an account opens at 50 shippers, can run past 100, and where several organizations need different slices of the same fleet. We struggled to sign those deals because our system couldn't do that well.

Underneath sat a core requirement. No organization could ever see another's data. This was not a bug to fix later. In healthcare it is the thing that ends a sale.

The role and the scope get picked together. The permissions are written out before the invite sends for added clarity. Customized permissions is on the roadmap.

The approach

Parent and child model first, nothing else. Ship it before month one of the pilot was out, prove the architecture, then widen it. We pushed to production in week four and walked the courier through it. The two months that followed went to watching them use it and making small adjustments.

What to call it

The engineering term is parent and child organizations. It's accurate. It's also a phrase nobody at a courier uses about their own clients, and the hierarchy is backwards. Parent orgs, entities, and sub-organizations were all considered and dropped for the same two reasons. They rank the hospital under the courier, or they're clunky.

A second constraint came from customers who weren't in the room. A courier is one customer type of several at Artyc. A clinical trial site would group by trial rather than by client, with its sponsor looking in. Another operator might group by region. The word had to be loose enough to hold a hospital this year and a trial or a region next year.

The user-facing word became Group.

How deep the hierarchy goes

The customer in front of us needed two levels: themselves (the courier), and the organizations it delivers for. We set the requirements at two explicitly and listed anything deeper as a future item.

The problem is who comes next. Contract research organizations run cold chain for pharma sponsors, and each sponsor runs several studies. That's three levels, and it's a large market. A prospect needing three would either be told no, or squashed into two by collapsing sponsor and study into one Group, which loses the isolation that made the feature worth having.

The schema and the interface don't have to agree. Groups gained one nullable column pointing at another Group. The application layer refuses anything deeper than two, and the interface never mentions depth at all.

The cheap insurance is to make the schema reversible by software now and the interface reversible by product later.

Excerpt from the architecture memo

One column, added before a customer asked for it, is the difference between a scoping conversation and a data migration. It cost almost nothing.

The third layer customers asked for turned out to be people, not organizations. A driver gets a record and a phone number. No added seat and nobody to onboard.

What landed

The manual loop is gone. The courier's operations lead exports nothing and emails nobody, because the hospital signs in and reads its own journeys. The pilot converted. A 40 unit purchase order at the end of the pilot. The sharing model was a big part of closing it. Since then, larger purchase orders from other couriers have landed and this data model is something they all asked for.

The courier we built it with has since been acquired by a national medical logistics network. That takes the model from one Bay Area operation to a network of subsidiaries, each with hospital clients of its own, and the same courier-and-client shape multiplied across it.

A driver gets a record and a phone number. No seat, no login, nobody to onboard.

What I’d do differently

During the pilot, the courier came back asking for a third layer, and it wasn't the one I'd hedged for.

They wanted to match drivers to specific shippers. People, not organizations. What those people didn't need mattered more than what they did: no account to onboard, no calendar, no login, no seat. Somebody the system refers to rather than somebody who uses it.

The nullable column did nothing for that. I'd bought flexibility along the axis I could picture, which was organizational depth, and the demand arrived along one I hadn't, which was entity type. A driver is not a small organization. Modeling them as one would have handed every courier a pile of empty tenants to administer, which is exactly the overhead they'd been telling us they didn't want.

The first version of field personnel shipped inside the pilot window. By the end of three months they were assigning drivers to shippers with it. The name is Field Personnel rather than drivers for the same reason the sharing model is called Group. Drivers is the courier's word. A clinical trial site has lab technicians handling shippers. Somewhere else it's a unit assigned to one named person. Same entity, different word at every customer, so the feature gets the word that belongs to none of them.

I don't think the hedge was wrong. It cost one column and it's still the right insurance against the hierarchy question. But it's a clean example of the thing I still don't have a method for. Being sure something will change is easy. Being right about which thing is a different problem, and buying flexibility everywhere is a slower way of building nothing.

The same command wherever you are. A journey joins a Group the same way a shipper does.

What’s still open

With the emailing gone, the work left is opening every journey to decide whether it mattered. So automated journey summaries are being built. An excursion narrative that gives a first read on what happened and, where the data supports it, why, with computed thermal headroom alongside. Natural-language fleet queries are moving through the command menu. The mechanics are still being prototyped, so that is as much as I'll claim for it.

Note: To respect confidentiality and regulatory compliance, interface images are built against the product's own design system and populated with fixture data. No customer records, colleague names, or partner names appear anywhere in this case.