Skip to main content

Civic engagement library: address → reps → delivery

Project description

GovPal Reach

Civic engagement library: discover representatives from an address and deliver messages via email or web forms. Resistbot-like functionality with modular, pluggable architecture.

Project overview

GovPal Reach maps address → representatives (federal, state, local) and supports message delivery via email (Postmark) or web forms (Playwright). Users onboard via SMS/OTP (Twilio Verify, or Plivo).

  • Discovery: Geocode address (Census Geocoder), then look up reps (Google Civic, Open States, LA local).
  • Delivery: Send messages via email or submit web forms; PGQueuer for durable queue.
  • Identity: User profiles, PII encryption, SMS OTP (Twilio primary, or Plivo).
  • Orchestrator: High-level API composing discovery and delivery.

Quick start

1. Install

Requires uv (install: curl -LsSf https://astral.sh/uv/install.sh | sh).

uv sync

2. Configure environment

Copy .env.example to .env and fill in values. See SETUP.md for how to obtain credentials.

cp .env.example .env
# Edit .env with your credentials

Email delivery mode (optional): GP_DELIVERY_MODE defaults to capture (no real sends) so new installs don't send email until you explicitly enable it. Set to live to send via Postmark.

  • capture (default) – No real sends; emails are recorded in memory for inspection (e.g. tests, CI).
  • redirect – All recipients are rewritten to the comma-separated addresses in GP_TEST_RECIPIENTS; subject is tagged with [TO: original].
  • live – Production behavior via Postmark (set explicitly to send real email).

3. Run a simple example

The library is intended to be imported by a host app. Example usage:

from govpal.orchestrator.api import discover_reps_for_address, send_message_to_representatives

# Discover reps for an address
reps = discover_reps_for_address("123 Main St, Los Angeles, CA 90012")

# Send a message to one or more representatives (library adds preamble + closing)
# body = middle content only; subject, profile, phone, and list of reps
results = send_message_to_representatives(
    "Your message body here.",
    "Subject line",
    profile,  # constituent profile (first_name, last_name, email, full_address_for_display)
    phone,
    reps,     # list of rep dicts with contact_email
)
# results = [(rep, success), ...]

4. Database (optional)

Apply the schema if using Postgres (Identity module requires 002 for OTP):

psql $DATABASE_URL -f schema/001_initial.sql
psql $DATABASE_URL -f schema/002_verify_session_uuid.sql

Modules

Module Responsibility
Discovery Address → reps (Google Civic, Open States, Census)
Delivery Email (Postmark), web forms (Playwright), queue
Identity Users, PII, SMS OTP (Twilio or Plivo)
Orchestrator High-level API: discovery, send_message_to_representatives (preamble + closing)

How to run the system

  • As a library: Import govpal in your app; configure env vars; use orchestrator API.
  • Production queue path: For durable delivery, use the queue path: create_message → optional update_messageenqueue_messages_for_address. Set GOVPAL_USE_REAL_QUEUE=1 and run the GovPal delivery worker so jobs are processed: uv run pgq run govpal.delivery.worker:create_pgqueuer --max-concurrent-tasks 2. See SETUP.md (PGQueuer section) for create_message/update_message usage and worker run command.
  • Railway: Deploy with Postgres; run the queue worker as a separate process or worker dyno; env vars set in Railway dashboard.

Using in another project

Install GovPal Reach as a dependency from PyPI (recommended for released versions):

# With uv (recommended)
uv add "govpal-reach>=0.2.0"

# Or with pip
pip install govpal-reach

To pin to a specific GitHub tag (e.g. before a version is on PyPI or to try a release tag):

uv add "govpal-reach @ git+https://github.com/YOUR_ORG/govpal-reach@v0.2.0"

Replace YOUR_ORG and the tag (v0.2.0) as needed. The import name is govpal:

from govpal.orchestrator.api import discover_reps_for_address, create_message, update_message, enqueue_messages_for_address

How to test

# Unit tests (runs in project .venv)
uv run pytest

# With coverage
uv run pytest --cov=govpal --cov-report=term-missing

# Integration tests (uses VCR cassettes; no live API calls by default)
uv run pytest -m integration

# Linter
uv run ruff check src/ tests/
uv run ruff format --check src/ tests/

Full test suite (lint + pytest + coverage): see TEST_PLAN_SUMMARY.md.

Documentation

  • RESEARCH_SUMMARY.md – APIs, data sources, architecture research
  • PLAN_SUMMARY.md – Implementation plan, beads, schema, modules
  • TEST_PLAN_SUMMARY.md – Testing strategy per phase
  • SETUP.md – External services, credentials, permissions; Releasing: push a v* tag and CI publishes to PyPI (Trusted Publishing), see section 13

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

govpal_reach-0.2.1.tar.gz (43.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

govpal_reach-0.2.1-py3-none-any.whl (53.8 kB view details)

Uploaded Python 3

File details

Details for the file govpal_reach-0.2.1.tar.gz.

File metadata

  • Download URL: govpal_reach-0.2.1.tar.gz
  • Upload date:
  • Size: 43.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for govpal_reach-0.2.1.tar.gz
Algorithm Hash digest
SHA256 2232fa1afb191759336e5a0bc4cc2e6ef0470c8d3b6a5856cb60fd5a7ff8e0cb
MD5 2f3dc81975c687fa42664e7055558628
BLAKE2b-256 5c8edf20b84c19619c6a632206e84d705d507637064e9138529ecabc7a8d970b

See more details on using hashes here.

Provenance

The following attestation bundles were made for govpal_reach-0.2.1.tar.gz:

Publisher: release.yml on BruceAndTyler/govpal-reach

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file govpal_reach-0.2.1-py3-none-any.whl.

File metadata

  • Download URL: govpal_reach-0.2.1-py3-none-any.whl
  • Upload date:
  • Size: 53.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for govpal_reach-0.2.1-py3-none-any.whl
Algorithm Hash digest
SHA256 41893674204f3e9438ca3ff29c296047e6c117b180f2a0742b564eefa8848faa
MD5 a636847fa77df21c118e851477e3aaa2
BLAKE2b-256 60fdbd9186ff89a88e18486b51da9c9b54c6eceb6ee585931d8a3680719289fe

See more details on using hashes here.

Provenance

The following attestation bundles were made for govpal_reach-0.2.1-py3-none-any.whl:

Publisher: release.yml on BruceAndTyler/govpal-reach

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page