ADR-0018: Announcement Entity Architecture

ADR-0018: Announcement Entity Architecture

Date: 2026-03-12 Status: Proposed Author: Stephen Groundwater Project: RSVP-System / Whitinghamvt.org Migration


Context

The Drupal 7 Whitinghamvt.org Announcement content type serves three roles in a single form:

  1. Announcement — time-bounded notice with auto-expiring publishing date range (default 180 days), highlight image, body/summary, external link, display location routing, and department assignment.
  2. Calendar Event — conditionally enabled via "Post to Calendar" checkbox, which reveals calendar taxonomy selection, event date/time with full RRULE recurrence support (daily/weekly/monthly/yearly, exceptions, additions).
  3. Document Filing — conditionally enabled via "Include File Cabinet Attachment" checkbox, which reveals file upload, document type classification, document filed date, and "List as Important" flag.

The town clerk creates all three workflows through a single form using conditional fields as mode switches. This pattern has been in production for over a decade and is well-understood by content editors.

RSVP-System's recipe cookbook architecture is designed for composability — discrete recipes that can be mixed and matched across different community types. The D7 "one form does everything" approach conflicts with this composability.

Decision

Option A: Composed Entities with References (Recommended)

Announcement is a standalone content type in the rsvp_announcement recipe. Calendar events and documents are separate entities (EventSeries/EventInstance per existing architecture, Document per rsvp_document recipe). Announcements reference these via entity reference fields.

  • field_event_reference — optional entity reference to EventSeries
  • field_document_reference — optional entity reference to Document (unlimited cardinality)

The form uses conditional fields or form modes: checking "Post to Calendar" reveals an inline entity form or autocomplete to create/reference an EventSeries. Checking "Attach Document" reveals an inline entity form or autocomplete to create/reference a Document.

Option B: Single Content Type with Conditional Fields

Replicate the D7 pattern directly. All event and document fields live on the Announcement content type, toggled by boolean fields. No entity references, no composition.

Rationale

Option A is recommended because:

  • Recipe composability. rsvp_announcement, rsvp_event, and rsvp_document remain independent recipes. A community that needs announcements but not events installs only rsvp_announcement. A community that needs events but not announcements installs only rsvp_event. The reference fields are added by a bridge recipe (rsvp_announcement_event, rsvp_announcement_document) that requires both base recipes.
  • Existing architecture alignment. The EventSeries/EventInstance model (ADR-0009) and the Document entity model are already designed. Embedding event fields directly on Announcement would duplicate the event data model and bypass the Recurring Events module integration.
  • Migration path. D7 announcements with calendar data migrate to: one Announcement node + one EventSeries entity + entity reference. D7 announcements with documents migrate to: one Announcement node + one Document node + entity reference. D7 announcements with neither migrate to: one Announcement node, no references. Clean separation.
  • Town clerk workflow preserved. Inline Entity Form (or a custom form mode) can present the same "check the box, fill in the fields" experience. The UX change is minimal. The data model change is structural.

Option B rejected because:

  • Breaks recipe composability — every community that installs rsvp_announcement gets event and document fields whether they need them or not.
  • Duplicates the event data model already defined in ADR-0009.
  • Makes Views and search integration harder — querying "all events" requires checking both EventSeries entities and Announcement nodes with calendar data enabled.

Consequences

Positive:

  • Each recipe remains independently installable and testable.
  • Events created from Announcements appear in all event Views and calendar displays without special filtering.
  • Documents attached to Announcements appear in the File Cabinet / Document search without special filtering.
  • The bridge recipes (rsvp_announcement_event, rsvp_announcement_document) are small — they add entity reference fields and form configuration only.

Negative:

  • Inline Entity Form or equivalent is required for the "create event from announcement" workflow. This adds a module dependency.
  • The migration is slightly more complex — D7 announcement rows must be split into multiple D11 entities with references.
  • Content editors create two entities (Announcement + Event) instead of one. Mitigated by inline forms, but the mental model shifts.

Bridge Recipes

rsvp_announcement              — core announcement fields only
rsvp_announcement_event        — requires rsvp_announcement + rsvp_event
                                 adds field_event_reference to Announcement
                                 adds inline entity form configuration
rsvp_announcement_document     — requires rsvp_announcement + rsvp_document
                                 adds field_document_reference to Announcement
                                 adds inline entity form configuration

Related ADRs

  • ADR-0009: Recipe Cookbook Structure
  • ADR-0009 (Event): EventSeries/EventInstance with Recurring Events Module
  • ADR-0003: Taxonomy-Driven Community Architecture
  • ADR-XXXX: Document Entity Architecture (pending)

Open Questions

  1. Should field_display_location (the 60-value placement system) become a taxonomy vocabulary, a paragraphs-based placement model, or a Block/Layout Builder placement? The D7 approach of hardcoded string values will not scale to other communities.
  2. Should the publishing date range (auto-expire) be part of rsvp_announcement or extracted into a reusable field recipe that other content types can use? The pattern is useful beyond announcements.
  3. For the Whitinghamvt migration specifically: should we run a parallel period where both D7 and D11 announcements are active, or do a hard cutover?