---
title: "MeasureCamp"
canonical: "https://www.owox.com/data-models/measurecamp"
updated: "2026-09-26"
---

# MeasureCamp Data Model

11 data marts61 fields[Vlad Flaks](https://www.linkedin.com/in/vladflaks)[Peter O’Neill](https://www.linkedin.com/in/peteroneill)

An unconference put on by local volunteers in one city on one day, where tickets become attendees, a board of rooms and time slots fills with session cards on the morning, and sponsors pay for the venue.

## Overview

MeasureCamp is an unconference for the data and analytics community: a free one-day event with no programme announced in advance, where the schedule is built on the morning by the people who turned up. This model describes how one runs. Each edition is put on by its own local volunteer committee in one city on one day; it opens with a session board — a grid of rooms against time slots — and attendees claim a place on it by writing a session card and pinning it up. Around that sit the things that make the day possible: the tickets that are the only way in, the people behind them, the committee roles that had to be filled, and the sponsors whose money pays for the venue and whose names end up on the rooms.

The model is built around two distinctions that are easy to lose and expensive to get wrong. Registering is not attending — a ticket is a claim on a place and an attendee is someone who took it, and the gap between the two is what an organiser wants to know before the day. And the board's size is a decision, not an outcome: rooms times session slots is how many sessions the day could hold, which is the denominator behind the standard post-event questions — was the board full, and was there enough variety on it.

**Scope:** this is the shape of the event, not a ledger and not an audience tracker. Sponsorship is the only money in it and there are no costs, so whether an edition covered its outgoings cannot be answered here. Nor is attendance at individual sessions recorded: who led a session is known, who sat in it is not.

## Example Questions

*   How full did each board get — of the `rooms` times session slots a `session board` offered, how many carried an actual `session`, and which editions left the most space unused?
*   Was the programme varied or lopsided — how did an edition's `sessions` spread across level, type and audience, and did any board end up with nothing for beginners?
*   How far is registering from attending — what share of `tickets` turned into `attendees`, how many of those were first-timers, and does the gap differ by `city`?

[Explore on canvas →](https://model.owox.com/?okf=https://github.com/OWOX/models/tree/main/bundles/measurecamp)

## Attendee

The people who actually turned up: one row per ticket that was used on the day. Registering and attending are deliberately separate here — a ticket is a claim on a place, an attendee is someone who took it — and the gap between the two is the number every organiser wants before the event. The two flags are what an edition would want to know about the room: whether this is someone's first MeasureCamp or a return visit, and whether they ended up leading a session, which any attendee may do by putting a card on the board. Who sat in which session is not tracked, and no join in this model implies it.

### Fields

| Column | Type | Alias | Description |
| --- | --- | --- | --- |
| `attendee_id` | STRING | Attendee ID | PK. Unique attendee identifier. |
| `ticket_id` | STRING | Ticket ID | The registration this attendee walked in on. Every attendee has one — no ticket, no entry — but not every ticket becomes an attendee. FK to [Ticket](#mart-ticket) |
| `is_first_measurecamp` | BOOLEAN | First MeasureCamp | True when this is the attendee's first MeasureCamp, false for a returning one. The new-versus-returning mix is the single best read on whether the community is growing or circulating. |
| `is_speaker` | BOOLEAN | Is Speaker | True when this attendee led at least one session. Leading does not stop someone attending other sessions, so speakers are a subset of attendees, not a separate group. |

### Relationships

| Related data mart | On | Cardinality | Meaning |
| --- | --- | --- | --- |
| [Ticket](#mart-ticket) | `ticket_id = ticket_id` | 1:1 | The registration this attendee walked in on. |

## City

The cities MeasureCamp runs in. One row per city, so the editions held in the same place across different years resolve to a single row and can be compared over time — which a free-text city name on the event could never do. A small lookup: it carries no dates and no numbers of its own, and is always read through an event.

### Fields

| Column | Type | Alias | Description |
| --- | --- | --- | --- |
| `city_id` | STRING | City ID | PK. Unique city identifier. |
| `name` | STRING | City Name | The city an edition is held in — London, Toronto, Delhi. One row per city, however many editions it has hosted. |

## Event

One row per edition of MeasureCamp: a single day, in one city, at one venue. Every edition is run by its own local organising committee rather than centrally, so an event is the unit that everything else in this model hangs off — the session board laid out for it, the tickets sold for it, the sponsors who funded it and the committee that put it on. The properties are deliberately few, because an edition is described by what happened around it far more than by its own attributes.

### Fields

| Column | Type | Alias | Description |
| --- | --- | --- | --- |
| `event_id` | STRING | Event ID | PK. Unique event identifier. |
| `city_id` | STRING | City ID | The city this edition was held in. FK to [City](#mart-city) |
| `name` | STRING | Event Name | Name of the edition, usually the city and the year. |
| `date` | DATE | Event Date | The single day the edition runs on — MeasureCamp is a one-day unconference. |
| `location` | STRING | Venue | The venue inside the city: the building that hosts the day. |

### Relationships

| Related data mart | On | Cardinality | Meaning |
| --- | --- | --- | --- |
| [City](#mart-city) | `city_id = city_id` | N:1 | The city this edition was held in. |

## Organizer

The local committee that puts an edition on. MeasureCamp is not run centrally: each event is organised by volunteers in that city, and this mart is one row per person per role they hold on one edition's committee — so someone who runs both the newsletter and the ticket releases appears twice, and someone who organises two years running appears in both. The roles are the working parts of an event: sponsors, venue, catering, finance, social media, newsletter, website, tickets and the afterparty.

### Fields

| Column | Type | Alias | Description |
| --- | --- | --- | --- |
| `organizer_id` | STRING | Organizer ID | PK. Unique organizer identifier. |
| `event_id` | STRING | Event ID | The edition this committee seat belongs to. FK to [Event](#mart-event) |
| `person_id` | STRING | Person ID | The individual holding the seat. FK to [Person](#mart-person) |
| `committee_role` | STRING | Committee Role | The job on the committee: `Sponsors`, `Venue`, `Catering`, `Finance`, `Social Media`, `Newsletter`, `Website`, `Tickets`, `Afterparty`. One row per person per role, so counting rows counts roles, not people. |
| `contact_details` | STRING | Contact Details | How to reach the organiser — a phone number or an address. |

### Relationships

| Related data mart | On | Cardinality | Meaning |
| --- | --- | --- | --- |
| [Event](#mart-event) | `event_id = event_id` | N:1 | The edition this committee seat belongs to. |
| [Person](#mart-person) | `person_id = person_id` | N:1 | The individual holding the seat. |

## Person

The individuals behind everything else in the model: one row per human, held once and reused across editions. A person becomes a ticket holder when they register, an attendee when they turn up and an organiser when they take a seat on a committee — so the same row can play all three roles, in the same year or in different ones. The professional attributes here — the organisation someone works for and what they do there — are what turn "how many people came" into a picture of who the community actually is.

### Fields

| Column | Type | Alias | Description |
| --- | --- | --- | --- |
| `person_id` | STRING | Person ID | PK. Unique person identifier. |
| `name` | STRING | Full Name | The person's name. |
| `email` | STRING | Email | Email address the person registers under. |
| `organization` | STRING | Organization | The company or organisation they work for. |
| `job_title` | STRING | Job Title | What they do — analyst, developer, marketer and so on. The mix of job titles is the closest thing the model has to a profile of the room. |

## Room

The rooms an edition's session board is built from: one row per room offered on a board, with the name it goes by, how many people it seats and how the seating is laid out. Rooms are usually named after the sponsor that paid for them, which is why a room points at a sponsor as well as at its board — an unsponsored room simply carries no sponsor. Capacity and layout are what decide whether a popular session has room for the people who want it: a boardroom of twelve and a theatre of a hundred are both one column of the grid, and the board itself does not distinguish them.

### Fields

| Column | Type | Alias | Description |
| --- | --- | --- | --- |
| `room_id` | STRING | Room ID | PK. Unique room identifier. |
| `session_board_id` | STRING | Session Board ID | The board this room is one column of. FK to [Session Board](#mart-session-board) |
| `sponsor_id` | STRING | Sponsor ID | The sponsor the room is named after. NULL for rooms that carry no sponsor's name. FK to [Sponsor](#mart-sponsor) |
| `name` | STRING | Room Name | What the room is called on the board — often the naming sponsor's brand. |
| `capacity` | INTEGER | Capacity | How many people the room seats as laid out. Read it together with `style`: the same space seats very different numbers as a boardroom and as a theatre. |
| `style` | STRING | Layout Style | Seating layout: `Boardroom` (a table, a dozen or so people, discussion-shaped) or `Theatre` (rows facing a speaker). |

### Relationships

| Related data mart | On | Cardinality | Meaning |
| --- | --- | --- | --- |
| [Session Board](#mart-session-board) | `session_board_id = session_board_id` | N:1 | The board this room is one column of. |
| [Sponsor](#mart-sponsor) | `sponsor_id = sponsor_id` | N:1 | The sponsor the room is named after; absent on unsponsored rooms. |

## Session

The talks themselves — at MeasureCamp, a session card an attendee writes and places on the board to claim a room and a time slot. There is no programme committee and no call for papers: the schedule is made on the morning of the event by the people who turned up, which is why a session points at the attendee who leads it rather than at a separate speaker. A card can exist before it has a place on the grid, so a session with no room and no time slot is one that was offered but never made it onto the board. The descriptive columns — type, level, language and the nature of the audience — are what answer the second post-event question after "was the board full": was there enough variety on it.

### Fields

| Column | Type | Alias | Description |
| --- | --- | --- | --- |
| `session_id` | STRING | Session ID | PK. Unique session identifier. |
| `session_board_id` | STRING | Session Board ID | The board this session card was placed on. FK to [Session Board](#mart-session-board) |
| `room_id` | STRING | Room ID | The room the session runs in. NULL while the card has not been placed on the board yet. FK to [Room](#mart-room) |
| `time_slot_id` | STRING | Time Slot ID | The slot the session runs in. NULL while the card has not been placed on the board yet — a session with no slot never actually happened. FK to [Time Slot](#mart-time-slot) |
| `speaker_attendee_id` | STRING | Speaker | The attendee who leads the session. Attendees both give sessions and sit in other people's, so this is a role on the day, not a separate kind of person. FK to [Attendee](#mart-attendee) |
| `name` | STRING | Session Name | The title written on the session card. |
| `description` | STRING | Session Description | What the session is about, as pitched on the card. |
| `type` | STRING | Session Type | `Presentation` (someone presents) or `Discussion` (the room talks). |
| `level` | STRING | Level | `Beginner`, `Intermediate` or `Advanced`. A board with nothing for beginners is a recognised failure mode, so the spread matters more than the count. |
| `language` | STRING | Language | The language the session is held in. |
| `audience` | STRING | Audience | The nature of the audience the session is pitched at: `Analytical`, `Business` or `Technical`. |

### Relationships

| Related data mart | On | Cardinality | Meaning |
| --- | --- | --- | --- |
| [Session Board](#mart-session-board) | `session_board_id = session_board_id` | N:1 | The board this session card was placed on. |
| [Room](#mart-room) | `room_id = room_id` | N:1 | The room it runs in; absent while the card is not yet on the board. |
| [Time Slot](#mart-time-slot) | `time_slot_id = time_slot_id` | N:1 | The slot it runs in; absent while the card is not yet on the board. |
| [Attendee](#mart-attendee) | `speaker_attendee_id = attendee_id` | N:1 | The attendee leading it — one attendee may lead several. |

## Session Board

The grid each edition is built around: one board per event, defined by how many rooms and how many session-length time slots the organisers put up. A board is a matrix — rooms on one axis, time slots on the other — and attendees fill it on the morning of the event by placing session cards on it. The three numbers here are static parameters set when the board is laid out, not counts of what happened: they are the capacity of the grid, so rooms times session slots is how many sessions the day _could_ hold. Comparing that to the sessions actually placed is the standard post-event question — how full was the board — and the usual answer is that a handful of slots stay empty.

### Fields

| Column | Type | Alias | Description |
| --- | --- | --- | --- |
| `session_board_id` | STRING | Session Board ID | PK. Unique session board identifier. |
| `event_id` | STRING | Event ID | The edition this board belongs to — exactly one board per event. FK to [Event](#mart-event) |
| `number_of_rooms` | INTEGER | Number of Rooms | Rooms the organisers put on the board. A static parameter of the layout, not a count of the rooms that ended up being used — organisers routinely plan one room fewer than they need. |
| `number_of_session_slots` | INTEGER | Number of Session Slots | Time slots reserved for sessions, excluding breaks and lunch. Static. `number_of_rooms * number_of_session_slots` is how many sessions the day can hold — the denominator for any "how full was the board" question. |
| `session_length_minutes` | INTEGER | Session Length (min) | How long one session runs on this board — traditionally 30 minutes, 25 at some editions. Set per board, so it is the same for every session on it. |

### Relationships

| Related data mart | On | Cardinality | Meaning |
| --- | --- | --- | --- |
| [Event](#mart-event) | `event_id = event_id` | 1:1 | The edition this board lays out — one board per event. |

## Sponsor

The organisations funding an edition: one row per sponsorship, per event, so a company that backs the same city three years running is three rows. A sponsorship carries a tier and a place in the pipeline, from a prospect being talked to, through confirmed, to actually paid — which is the difference between a budget an organiser can spend and one they only hope for. Sponsors show up elsewhere in the day too: the rooms are usually named after them, and their staff come in on tickets of their own. Note the boundary — this is the money coming in; the model has no costs side, so "did the event cover its costs" cannot be answered here.

### Fields

| Column | Type | Alias | Description |
| --- | --- | --- | --- |
| `sponsor_id` | STRING | Sponsor ID | PK. Unique sponsorship identifier. |
| `event_id` | STRING | Event ID | The edition this sponsorship was bought for — sponsorship is always per event. FK to [Event](#mart-event) |
| `organization_name` | STRING | Organization Name | The sponsoring company, as it appears on the room and the banners. |
| `tier` | STRING | Tier | Sponsorship level: `Gold`, `Silver` or `Bronze`. |
| `status` | STRING | Status | Where the sponsorship stands: `Prospect` (in conversation), `Confirmed` (agreed) or `Paid` (money received). Only `Paid` is money an organiser actually has. |

### Relationships

| Related data mart | On | Cardinality | Meaning |
| --- | --- | --- | --- |
| [Event](#mart-event) | `event_id = event_id` | N:1 | The edition this sponsorship was bought for. |

## Ticket

Registration: one row per ticket issued for an edition, and the only way in — the rule is that without a ticket you do not get through the door. A ticket names the person it belongs to and the capacity they come in as, since sponsors, organisers and volunteers are all ticket holders too rather than a separate list. Tickets are released in batches, which is what makes a release number worth keeping. And because not everyone who registers arrives, the count of tickets is always larger than the count of attendees — treating the two as the same number is the classic mistake this split exists to prevent.

### Fields

| Column | Type | Alias | Description |
| --- | --- | --- | --- |
| `ticket_id` | STRING | Ticket ID | PK. Unique ticket identifier. |
| `event_id` | STRING | Event ID | The edition this ticket admits to. FK to [Event](#mart-event) |
| `person_id` | STRING | Person ID | The individual the ticket belongs to. The same person across editions is the same row in Person, which is what makes returning visitors visible. FK to [Person](#mart-person) |
| `sponsor_id` | STRING | Sponsor ID | The sponsor whose allocation this ticket came out of, for sponsor staff. NULL for every ordinary ticket. FK to [Sponsor](#mart-sponsor) |
| `type` | STRING | Ticket Type | The capacity the holder comes in as: `General Attendee`, `Sponsor`, `Organizer` or `Volunteer`. |
| `release` | INTEGER | Ticket Release | Which batch the ticket was released in — 1 for the first release, 2 for the second, and so on. |
| `sponsor_consent` | BOOLEAN | Sponsor Consent | True when the holder agreed at registration that their details may be shared with the edition's sponsors. |

### Relationships

| Related data mart | On | Cardinality | Meaning |
| --- | --- | --- | --- |
| [Event](#mart-event) | `event_id = event_id` | N:1 | The edition this ticket admits to. |
| [Person](#mart-person) | `person_id = person_id` | N:1 | The individual the ticket belongs to. |
| [Sponsor](#mart-sponsor) | `sponsor_id = sponsor_id` | N:1 | The sponsor whose allocation issued it; absent on ordinary tickets. |

## Time Slot

The other axis of the session board: the day cut into named slots. Not every slot is for sessions — the morning break, lunch, the afternoon break, the closing and the party are slots too, and they are what make the schedule readable as a day rather than a list of talks. Only the session-type slots can carry a session card, so the type is the filter that turns "slots in the day" into "slots a session could go in", and getting that wrong understates how full a board really was.

### Fields

| Column | Type | Alias | Description |
| --- | --- | --- | --- |
| `time_slot_id` | STRING | Time Slot ID | PK. Unique time slot identifier. |
| `session_board_id` | STRING | Session Board ID | The board this slot is one row of. FK to [Session Board](#mart-session-board) |
| `name` | STRING | Time Slot Name | What the slot is called on the board, e.g. `Session 1`. |
| `type` | STRING | Slot Type | `Session`, `Morning Break`, `Lunch`, `Afternoon Break`, `Closing` or `Party`. Only `Session` slots carry sessions — filter on this before counting slots against the sessions placed in them. |
| `start_time` | TIMESTAMP | Start Time | When the slot starts. |
| `end_time` | TIMESTAMP | End Time | When the slot ends. |

### Relationships

| Related data mart | On | Cardinality | Meaning |
| --- | --- | --- | --- |
| [Session Board](#mart-session-board) | `session_board_id = session_board_id` | N:1 | The board this slot is one row of. |

## Apply to your project

1.  1

    ### Install the Import Model plugin

    One plugin, installed once, in your own OWOX workspace.

    [Get the plugin →](https://github.com/OWOX/import-model)

2.  2

    ### Import this model

    Point it at this bundle and it creates every data mart above, joins and all.

    [Open the model →](https://model.owox.com/?okf=https://github.com/OWOX/models/tree/main/bundles/measurecamp)

3.  3

    ### Plug in your data and destinations

    Connect your own sources and send the results where your team already works.

    [Browse connectors →](/connectors)

**4\. Optional — customize as you wish.** Rename a column, drop a mart, add your own: once it is imported it is yours, and nothing here syncs back.

## References

Pages this page links to, on this site and on docs.owox.com. Where the page has a Markdown twin, its address follows the link.

- [Browse connectors →](https://www.owox.com/connectors) — /connectors.md
