CivicNexus
I helped turn CivicNexus from a legislative tracking app into a legislative response platform: software that helps policy teams notice the right bills, decide what to do, prepare testimony, and act before deadlines pass.
The work combined product strategy and full-stack implementation. I reframed the product around the real job policy teams need done, then built the architecture that could support it: same-origin edge routing, durable notification state, testimony document generation, hearing calendar feeds, feedback intake, analytics, operations docs, and tests around workflows that cannot fail during session.
- Problem
- Policy teams needed to move from passive bill tracking to timely legislative response.
- Role
- Product strategy, full-stack engineering, edge architecture, UX, testing, docs, and GTM site.
- Changed
- Dashboard, saved lists, notifications, testimony generation, hearings feeds, feedback intake, and public marketing.
- Proof
- Worker routes, Durable Objects, queues, D1 migrations, GCS signed URLs, Sentry, PostHog, Playwright flows, runbooks, docs, pricing, and demo capture.
At A Glance
- Product: reframed bill tracking as legislative response.
- UX: rebuilt the dashboard and bills workbench around lists and action.
- Platform: moved the app edge to Cloudflare Workers without losing the legacy backend.
- Workflows: built notifications, testimony DOCX generation, hearings feeds, and feedback intake.
- Operations: added Sentry, PostHog, tests, runbooks, release docs, and guardrails.
- Go-to-market: built the public website so the product could be understood, sold, and supported.
The Problem
Policy professionals are not just browsing legislation. During session, they are trying to answer a more urgent question: what changed, what matters to us, and what do we need to do before the deadline?
The earlier CivicNexus app had the pieces of a tracker: dashboard, bills, hearings, testimony, organizations, users, and admin settings. But the product still leaned toward displaying data. The higher-value opportunity was helping users move through the whole response cycle: awareness, decision, execution, and record.
When I joined, the frontend codebase had been assembled quickly around a promising vision, but it was difficult to extend and the user experience was uneven. Before layering on new capabilities, I tidied and modernized the codebase so the product had a more reliable foundation for real user work.
Foundation First
The first job was not adding features. It was turning a fragile frontend into something that could support a serious product. I cleaned up the structure, clarified the product model, and made the user experience less accidental before building new workflows on top of it.
Product Model
I changed the product model from “track bills” to “respond before deadlines pass.” Bills remained the core object, but the organization's relationship to each bill became first-class: stance, action, priority, assignments, saved lists, notification settings, testimony artifacts, and reports.
That gave the work a clearer product direction. The app should not require users to constantly ask "what's happening?" The system should push relevant changes to them, then help them decide and act when human judgment is required.
Product Workspace
I rewrote and redesigned the web application dashboard. The earlier dashboard showed a welcome message, basic counts, and a short recent-legislation card. The new dashboard became an operational workspace with a persistent app shell, sidebar navigation, top search, organization switching, notification surfaces, list-driven overview cards, and upcoming hearings.
The biggest UX change was making lists the center of the product. A list is a saved filter set that can be personal or shared across an organization. Lists can be created from the filter drawer, edited, pinned for quick access, shown on the dashboard with live bill counts and breakdowns, and connected to notification settings.
Making It Sellable
I built a new public marketing website for CivicNexus so the product could be understood outside the app. That work translated the strategy into pages that could explain, sell, and support the product: homepage, product page, pricing, demo request flow, solution pages, industry pages, comparison pages, release notes, resources, docs, glossary pages, and public bill pages.
The site framed CivicNexus around "first to know, first to act," showed the detect-decide-deliver workflow, explained lists and notifications in public docs, published release notes, and created SEO-oriented legislative content with canonical bill pages, sitemaps, structured data, Open Graph metadata, and accessibility checks.
Edge Architecture
I moved the application edge to Cloudflare Workers and served the SPA through Worker Static Assets. The Worker became the same-origin request layer for the app: serving frontend assets, proxying legacy backend APIs, and hosting new product routes without forcing every new capability into the older backend.
This mattered because the product needed a place for new capabilities to live without forcing everything through the legacy backend. Request handling, feature APIs, durable workflow state, async delivery, and static assets could now live together at the edge.
Change Notifications
I built the notification model around saved bill filters. When bill data flows through the app, the Worker fans snapshots to a Durable Object, detects relevant changes, matches them against user and organization subscriptions, stores in-app notifications, enqueues immediate delivery, or collects changes into digests.
That made notifications a real product capability instead of a thin alert UI. It added delivery attempt tracking, dedupe, digest state, Slack and email delivery, admin observability, runbooks, and tests around failure isolation and queue behavior.
Legislation Workbench
I rebuilt the bills page into a denser workbench for session-time analysis. The header supports fast search, introduced-year or last-update-year filtering, an active-bills toggle, priority filtering, pinned lists, list management, export, and a filter drawer for deeper query building.
The filter model expanded beyond simple search and status fields. It supports action, lifecycle, status, priority, tags, relevance range, deadlines, committees, originating and current chamber, bill type, fiscal impact, referral count, referral committees, joint referrals, introducers, and sponsor-role filters. Filter options are indexed ahead of time so opening the drawer does not have to recompute the world.
I also added multi-column sorting. Users can sort by bill number, title, status, deadline, relevance, action, and priority, with stable tie-breakers so high-priority work stays predictable. In the table implementation, Shift+click adds secondary sorts and Cmd/Ctrl+click removes a column from the sort stack; the Data Grid variant maps the same sort model into MUI's grid sorting.
User Feedback Loop
I built a feedback interface directly into the new web application so users could report bugs, ask questions, and suggest features without leaving their workflow. The feedback entry point was available from the top bar and side navigation, opened a lightweight dialog, and captured the category, message, user email, organization, role, and timestamp.
Submissions posted to a Worker route and went straight into a Slack channel for the team to review. That closed the loop between product usage and product development: feedback did not sit in an inbox or disappear into analytics, it showed up where the team already discussed the work.
Testimony Workflow
Testimony became a first-class execution workflow. Organizations can upload DOCX templates, store template metadata in D1, keep generated document versions, and generate bill-specific testimony documents through Worker routes backed by Google Cloud Storage signed URLs.
I kept testimony document storage in Google Cloud Storage rather than forcing a move to Cloudflare R2, because the founder was already comfortable operating GCP. The Worker integrated with GCS through signed URLs, so the architecture matched both the product need and the team's operating reality.
The generation path enriches templates with bill, organization, stance, author, and hearing context. That connects tracking to execution: the app does not stop at "this bill matters"; it helps create the document a user needs to submit.
Hearings And Calendar
Hearings moved from static page content toward a live workflow. A ScheduledHearings Durable Object refreshes Hawaii hearing data, stores the latest snapshot, supports agenda parsing, and exposes an ICS feed so users can subscribe from Google Calendar, Outlook, or Apple Calendar.
This matters because legislative work is temporal. A tracker that does not understand hearings and deadlines still leaves the user responsible for remembering when to act.
Operating System
The rebuild also added the engineering scaffolding needed for a more ambitious product: route-level code splitting, feature flags, local Cloudflare development, D1 migrations, Durable Object schema migrations, Storybook, behavior-focused Vitest tests, worker contract tests, Playwright critical flows, accessibility docs, deployment docs, notification runbooks, error monitoring, and product analytics.
The test strategy emphasizes behavior at the cheapest reliable layer. For frontend behavior, that means real providers and focused seams. For edge workflows, it means worker tests around routes, Durable Objects, queues, delivery failures, subscriptions, ICS generation, bill progress parsing, and testimony generation.
I added Sentry for staging and production error monitoring, including release tracking, source-map uploads, API breadcrumbs, user and organization context, and support debug sessions. I also added PostHog for product analytics with pseudonymous identifiers and documented no-PII event tracking for bill search, saved lists, exports, tracking actions, and testimony drafting.
What Changed In Practice
- Product: from a client-heavy legislative tracker to an edge-backed response platform.
- Dashboard: from counts and recent bills to lists, hearings, notifications, and active work.
- Marketing: from product work hidden inside the app to a public website with positioning, pricing, docs, release notes, and demo capture.
- Filters: from temporary page state to reusable personal and organization lists.
- Sorting: from simple table sorting to multi-column sorting with stable work-oriented defaults.
- Feedback: from informal user reports to an in-app feedback flow routed into the team's Slack channel.
- Testimony: from a page-level feature to templates, generated DOCX versions, signed uploads, and storage.
- Hearings: from information to view to calendar subscriptions, agenda parsing, and deadline context.
- Architecture: from capabilities split across awkward infrastructure to Worker routes, Durable Objects, queues, D1, migrations, and runbooks.
My Role
I worked as a product-minded full-stack engineer across strategy, information architecture, frontend implementation, edge architecture, Worker routes, data modeling, testing, observability, operations docs, release infrastructure, and public-facing marketing. The work required keeping the legacy backend useful while creating a clearer place for new capabilities to live.
Why It Matters
This is the kind of work that only creates value when it is built, operated, and explained. The architecture reduced friction for future product work. The dashboard and lists made user workflows easier to repeat. The docs, runbooks, feedback flow, Sentry, and analytics made the product easier to learn from. The marketing site made the value visible to people who had not yet used the app.
What This Shows
- I can turn a broad product surface into a clearer workflow model.
- I can modernize architecture without throwing away a backend the product still depends on.
- I can use platform primitives when they map directly to product needs.
- I can connect frontend UX, edge services, storage, background work, and operations.
- I can communicate product value through positioning, docs, pricing, and a public website.
- I can make a product more ambitious while also making it easier to test and operate.