01. The Core Model

Three Structural Decisions

Idea 1

Events are the center

An event (screening, action fair, panel) is the most specific unit of work. It links a venue, a film, contacts, a date, and a time. Everything else connects through events.

Idea 2

One person, many roles

A single contact can be a host, a panelist, and a donor across different events. One record per person, with a role layer—not separate tables per function.

Idea 3

Canonical sources feed assembled outputs

Master data lives in a small number of canonical tables. Stakeholder-facing outputs (host pages, screening packets, email campaigns) are assembled from those sources. Data flows one direction: downstream.

02. Contacts + Roles

Contacts + Roles

The Pattern: Assignments Table

Contacts        One record per person — name, email, phone

Assignments     Junction table — links one Contact to one context (Org, Venue, Film, or Event) with a Role
    + Role (Host Contact, Filmmaker, AV Contact, Panelist, etc.)
    + Priority (Primary or Secondary)
    + Notes

One record per person. Roles come from Assignments, not from separate contact-type tables.

Venues Are Entities, Not Contacts

Venues have their own properties: address, capacity, AV tier, accessibility. People at venues are Contacts with a "Host Contact" or "AV Contact" Assignment linked to the Venue record.

03. Architecture Rings

Hub with Rings

Events at the center. Contacts, Venues, Films, and Organizations link through Assignments and Events. Data flows outward through assembly into stakeholder outputs.

Resilience Stakeholder Outputs Tracking + Operations Core Events Contacts + Assignments Venues Films Organizations Seasons Assets Deliverables Deliveries Comms Log Asset Versions Procedures Routing Rules Host Helper Pages Screening Packets Deliverables Email Campaigns Routing Rules Sync Scripts
LAYER 1: CORE (persistent, year-over-year)
  Seasons            One record per festival edition
  Contacts           All people — one record per person
  Organizations      Host orgs, sponsors, partners, production companies
  Venues             Physical spaces — capacity, ADA, AV, address
  Films              Titles, runtimes, licensing terms

LAYER 2: RELATIONAL (season-specific)
  Events             The relational hub — links venue + film + season + date/time
  Assignments        Junction table — one Contact + one context + one Role

LAYER 3: ASSET PIPELINE (populated during operations)
  Assets             Master index of all inbound/outbound files
  Asset Versions     QC history per file version
  Deliverables       Packaged outputs for stakeholders
  Deliveries         Who got what, when

LAYER 4: SUPPORTING (operational memory, persistent)
  Comms Log          Significant communications and engagements
  Procedures         Runbooks and SOPs
  Routing Rules      Decision trees encoded in data

OUTPUTS (assembled from canonical data, not stored in Airtable)
  Host Helper Pages  Generated HTML per venue — hosts.oneearthfilmfest.org
  Screening Packets  Bundled deliverables for day-of operations
  Email Campaigns    Merge data for outreach
Data flows one direction: Core tables feed relational tables. Relational tables feed the assembly layer. Assembly produces stakeholder outputs. Nothing flows back upstream.
04. Architecture Comparison

v1 (Venue-Centric) vs v2 (Event-Centric)

The venue-centric model broke when venues hosted multiple events—concatenated values, uneditable computed fields, and derived data that obscured what was actually stored.

v1 — Venue-Centric

  • Organizing principle: Venues
  • Multi-event venues: Concatenated with commas
  • Data chain: 3-layer derived fields (link → lookup → computed)
  • Editability: Can't edit derived fields
  • Contacts: Separate tables per contact type
  • Debugging: Trace the derivation chain to find the source

v2 — Event-Centric

  • Organizing principle: Events
  • Multi-event venues: One row per event, no ambiguity
  • Data chain: Flat text fields, script-assembled
  • Editability: Team edits flat fields directly
  • Contacts: Unified with role junction table
  • Debugging: What you see is what's stored
Core tradeoff: v2 duplicates data (every event row has its own copy of the venue address) in exchange for editability and clarity. The assembly script can re-flatten from canonical sources at any time without breaking manual edits in protected fields.
05. Architecture Decisions

8 Foundational Decisions

Decision 1

Events as relational key

Events are the most specific data level. They link to master tables (venues, films, contacts) rather than the reverse.

Decision 2

Assignments, not Contact Types

One record per person. Roles come from the Assignments junction table. A person holding multiple roles gets one Contact record with multiple Assignments.

Decision 3

Venues are entities, not contacts

Venues have properties contacts don't: address, capacity, AV tier, accessibility. People at venues are contacts with a "venue contact" role linked to a venue record.

Decision 4

Partnership categorization

Collaborators (mission-oriented) vs. transactional contacts (business relationship where money changes hands for a deliverable).

Decision 5

Organizations table covers all org types

Host orgs, sponsors, partners, production companies in one table with a Type field. Not separate tables per relationship type.

Decision 6

Per-event interface pages

Replace per-venue grid views with event-centric pages. Implemented as Host Helper Pages: generated HTML per venue at hosts.oneearthfilmfest.org, assembled from Airtable data by the host guide generator script.

Decision 7

Dual venue classification

Flagship/Community (team presence level) alongside T1–T4 (technical needs). Two separate systems, not competing.

Decision 8

"Events" umbrella term

"Screenings" becomes a subtype of "events." Events covers action fairs, concerts, panels. Future-proofs the data model.

06. Data Flow

How Data Moves Through the System

Three types of data source feed the system. Validated operational data (from hands-on coordinators). Team planning data (from shared planning documents). Relational structure (from the database). Scripts bridge all three.

Validated Ops Data contacts, venues, AV, films Contacts + Venues + Films
Team Planning scheduling, film assignments Events
Core Tables assembly script Host Helper (flat rows)
Host Helper interface layer Host-facing pages
Host Helper merge export Email campaigns
Key principle: Data flows downhill. Core tables feed events. Events feed the assembly layer. Assembly produces flat rows for stakeholder-facing outputs. No data flows upstream from outputs to core tables. Edits to canonical data trigger re-assembly; edits to protected output fields are preserved across re-runs.
07. Ownership Model

Script-Owned vs Team-Editable

The assembly layer has two kinds of fields. Script-owned fields are overwritten from canonical sources on every run. Team-editable fields are preserved—the script reads existing values first and only writes if blank.

Script-Owned (~21 fields)

  • Event identifiers and metadata
  • Film title, runtime, filmmaker contact
  • Screening date, time, doors
  • Venue name, address, capacity
  • Contact name, email, phone, role
  • Ticket URL, price, OEFF rep
  • Resource links (webinar, guide)

Team-Editable (~7 fields)

  • Parking instructions
  • Transit notes
  • WiFi details
  • AV notes
  • Volunteer needs
  • Screening packet URL
  • General notes
Why this matters: This ownership contract is what makes the system safe for collaborative editing. The team can work in the output layer without risk of being overwritten, and the technical coordinator can re-assemble from canonical data without risk of losing operational notes.
08. What Persists, What Resets

Year-Over-Year vs Seasonal

Some data carries forward between festival seasons. Other data is rebuilt fresh each year.

DataLifespanWhy
ContactsYear-over-yearPeople persist. Their roles may change between seasons.
VenuesYear-over-yearPhysical spaces don't change. AV specs, accessibility data persist. Contact person may rotate.
FilmsYear-over-yearA film may screen again in a future year. Licensing terms are season-specific.
OrganizationsYear-over-yearOrg records persist. Partnership tier and commitment are season-specific.
Scripts + toolingYear-over-yearUpdated between seasons. Versioned.
Architecture decisionsYear-over-yearRationale persists even if implementation changes.
EventsSeasonalCreated fresh each year. Link to persistent venues + films + contacts.
Host HelperSeasonalRebuilt by script each season.
Assets + DeliverablesSeasonalScreening copies, packets, kits are season-specific.
Comms campaignsSeasonalNew campaigns each year. Templates may carry over.
Design principle: Assignments handle the year-over-year/seasonal boundary. Contact records persist. Assignments link to Events (which are seasonal), so current-year and historical roles are naturally separated by Season.
09. Anti-Patterns

5 Structural Mistakes to Avoid

Failure modes from festival and nonprofit data architectures. The most common ones, not the exhaustive list.

1. Separate tables per contact type

What happens: Host Contacts, Film Contacts, Panelists, Sponsors all separate. One person appears in three tables. Email gets updated in one, not the others. Fix: Contacts + Assignments junction pattern.

2. Treating assembled outputs as canonical

What happens: Someone edits the host-facing page and assumes it flows back to the master data. It doesn't. Fix: Clear canonical/assembled distinction. Protected fields are labeled. Everything else is overwritten on re-assembly.

3. Routing via memory only

What happens: "Ask the technical coordinator" is the routing table. When they leave, routing knowledge leaves too. Fix: Routing Rules table that encodes "where does this go?" in data.

4. Silent bidirectional edits

What happens: Two systems editing the same field without ownership rules. Sync overwrites a human edit. Fix: Explicit script-owned vs team-editable split.

5. Over-normalizing too early

What happens: Many tiny tables with sparse usage. Junction tables for things that are actually 1:1. Fix: Add tables only for real many-to-many relationships or independent lifecycles. Every new table must answer: "what lifecycle can't a field represent?"

10. Handoff Resilience

What Survives Turnover

OEFF's main risk is continuity, not scale. The architecture prioritizes legibility for successors.

Role-Based Risk Map

RoleCreates / OwnsHandoff Risk If Role Vacated
Executive DirectorGreenlights, strategic decisions, budgetLow — decisions are documented; institutional memory is the risk
Technical CoordinatorScripts, sync pipelines, database schema, deploymentHigh — personal infrastructure (API keys, deployment accounts, cron jobs)
Host Comms CoordinatorOperational data, comms campaigns, host relationshipsMedium — flat tables reduce debugging burden; process knowledge is the risk
Digital CommunicationsTicketing, newsletter, social mediaLow — centralized platforms with org accounts
Creative AssetsVideo production, slide decks, experiential flowLow — assets live in shared Drive
The pattern: Centralized platforms (database, shared drive, ticketing) survive role changes. Personal infrastructure (scripts, deployment, API tokens) is the fragile layer. The Routing Rules and Integration Registry tables are designed to make personal infrastructure legible—not to centralize it overnight, but to document what exists so a successor can find it.
11. When to Outgrow This

Scale Transitions

At OEFF's current size (~22 confirmed screenings, 15 films, small seasonal team), a spreadsheet-friendly database + scripts is the right core.

TriggerWhat Changes
Submission volume outgrows manual intake mapping (>100/year)Add a formal submissions platform for inbound; keep the database for ops
Virtual/hybrid rights windows need integrated deliveryAdd a streaming/delivery platform alongside the database
Team grows beyond ~15 with department silosConsider a purpose-built festival management platform
Grid-style database can't handle junction table complexityMove to a relational database (PostgreSQL, SQLite) with a lightweight UI layer
Workforce complexity triggers the tool transition earlier than data size in contractor-heavy teams. The Assignments junction pattern works in a grid-style database today and migrates cleanly to a relational database later. Choose the tool based on who needs to edit the data day-to-day.