Software
Civic
Full-Stack Web Application
Searchable civic events, connected across list, map, and mobile.
Git-backed contributions · collaborative project- Role
- Full-Stack Contributor
- Stack

One place to discover participation.
Civic was built to make local civic participation easier to discover. The application brought events into one searchable experience with cause exploration, filters, map context, and detailed event pages.
The discovery problem
Civic events are fragmented by organizer, location, issue, date, and event type. A usable discovery product needed to let a user narrow the same event collection by several criteria while keeping list, map, and detail views consistent. Mobile needed its own controls, card layouts, loading states, and navigation.
My contribution, across the stack.
I contributed across both the frontend and backend. My work was concentrated in the early event-discovery architecture, mobile behavior, search and filtering, event-detail navigation, the landing/search experience, the Node/Express backend, CMS-backed event APIs, and the Mailchimp subscription path.
- Frontend
- Built the initial map-and-sidebar experience; implemented substantial mobile functionality, search relevance/autocomplete, composable filtering, readable event slugs, and the first-stage landing/search experience.
- Backend
- Built Node/Express setup and routing, CMS-backed event collection/detail APIs, migration from an early MongoDB prototype, and the server-side Mailchimp subscription flow.
Collaboration and attribution
The current frontend is the result of team evolution: several pages and the final centralized route composition were later refactored by other contributors. Final Google Maps rendering is shared. The current Explore Causes page is shown as product evidence, not as my implementation. Feature authorship and current-file ownership are not the same thing.
From a cause to an event.
The recovered application shows landing/search, event detail with map context, and cause exploration. These are product views from a local recovery, not evidence of an active production service.



One filtered collection. List and map in sync.
The application kept most event normalization and discovery logic in the frontend. The backend was primarily an integration boundary: it selected configured external endpoints, added CMS authorization, and proxied event responses.
- Normalize before sharing UI state
- React converts CmsEvent records into CivEvent, removes expired events, formats dates/tags, selects image fallbacks, and builds ID, slug, and tag indexes.
- Compose filters once
- Title relevance, event type, causes/tags, availability, and virtual status produce filteredEvents. The same collection drives both the event list and map markers.
Search and navigation
I implemented autocomplete, Enter-key submission, title-relevance helper logic and ordering, and corrections for empty search input. I introduced human-readable event slugs built from titles and IDs and connected them to event-detail and map-card navigation. The final centralized router evolved collaboratively.
Frontend and backend stack
React 17, React Router 6, TypeScript, JavaScript, Material UI, Axios, React Context, and the Google Maps JavaScript API formed the browser application. The integration backend used Node.js, Express, CMS HTTP APIs, and the Mailchimp Marketing API. MongoDB/Mongoose was an early event-storage prototype.
CMS collection and detail contracts
GET /post proxies the CMS collection; GET /post/:id provides a detail contract. The frontend normally resolves detail pages from its already-loaded global collection; the fallback detail fetch is commented out. The active backend uses Axios. The evidence supports CMS API integration, not ButterCMS SDK configuration or workspace administration.
Mailchimp and prototype limits
POST /mailchimp accepts the frontend email payload, lowercases the address for lookup, computes the subscriber hash, checks the audience, and creates a member when appropriate. Credentials stay server-side, but audience configuration was hardcoded, validation was limited, and response/error paths were not production hardened. Automated backend tests and successful Heroku deployment ownership are not established.
Mobile needed its own composition.
The mobile experience was treated as its own information architecture rather than only a narrower desktop layout. My contribution included mobile event cards, filters, list/map controls, loaders, online-event badges, and responsive event-page work.

A clear integration boundary.
React UI → Axios → Node / Express → CMS + Mailchimp. Service credentials and configured endpoints remain behind the backend boundary; event normalization, search, and filtering happen in React.
- CMS → Express GET /post
- { data: CmsEvent[] } → React
- CmsEvent → CivEvent normalization
- ID / slug / tag indexes
- Search + filters → filteredEvents
- Context → list + map; collection → detail
Subscription branch and configuration
Subscription form → POST /mailchimp → normalized email → subscriber hash → Mailchimp member lookup/create → frontend thank-you flow. I configured backend operation through environment variables and dynamic ports. MongoDB/Mongoose storage, Passport authentication, Google geocoding, and Handlebars views were historical prototypes, not production-ready capabilities.
Functional results. Transferable lessons.
Civic reached a functional full-stack state with searchable and filterable civic events, list/map discovery, event-detail pages, responsive/mobile behavior, CMS-backed event delivery, and an email-subscription integration. The original frontend was later restored locally using an offline event fixture so it could be documented without the retired production backend.
- Share a source of truth
- Normalize external data before distributing it through UI state, and derive multiple presentations from one filtered collection.
- Design behavior across boundaries
- Treat URL state as part of navigation, give mobile the composition it needs, and keep service credentials behind the backend.
- Describe the maturity the evidence supports
- Prototype integrations are not production-hardening claims. Collaborative feature authorship is distinct from owning every current page.
Contributions grounded in evidence.
The contribution audit covers frontend and backend history, recovered screenshots, route/component mappings, and a curated commit manifest. The full source package is retained internally; this page presents the claim boundaries rather than a raw Git log.