Democracy.cc initially covered City Commission and Historic Preservation Board meetings. When I needed to add Land Use & Sustainability Committee (LUSC) support, the question was: how much would need to change?

The Difference

LUSC items are policy discussions -- no case numbers, no property addresses, no hearing types. Commission items have structured data (case C-2024-001, 123 Ocean Drive, Type II variance). The existing agenda-card Blade component expected that structure.

The Fix: 5 Lines

Instead of building a new component, I added a boardRoute parameter to the existing one:

// agenda-card.blade.php
@props(['item', 'boardRoute' => 'agenda'])

<a href="{{ route($boardRoute . '.show', $item->id) }}">
    {{-- All existing card markup --}}
</a>

LUSC pages pass boardRoute="lusc", commission pages use the default. Same card, different routing. The component already handled missing case numbers and addresses gracefully -- it just didn't render those sections when the data was null.

Sponsors via Metadata

LUSC items list sponsors differently than commission items (in PrimeGov metadata rather than structured fields). Rather than adding LUSC-specific parsing, I added a metadata fallback:

public function getSponsorsAttribute(): array
{
    if (!empty($this->attributes['sponsors'])) {
        return json_decode($this->attributes['sponsors'], true);
    }
    // Fallback: extract from PrimeGov metadata
    return $this->extractSponsorsFromMetadata();
}

Commission items use the primary path. LUSC items fall through to metadata extraction. Both work through the same accessor.

The Lesson

The best architecture decision here was the one I made months earlier: building the agenda card as a flexible component that handles missing data gracefully. Adding a new meeting type was a 5-line change, not a rebuild. When you're tempted to build specialized components, consider whether the general one can handle the variation.