Programs Database
The programs table is the heart of Pathfinder—a structured catalog of 2,500+ federal, state, and local benefit programs.
Schema Design
The programs table stores everything needed to display, search, filter, and match benefit programs.CREATE TABLE programs (
-- Identity
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
slug TEXT UNIQUE NOT NULL, -- URL-friendly identifier
name TEXT NOT NULL, -- "Supplemental Nutrition Assistance Program"
short_name TEXT, -- "SNAP"
-- Classification
category TEXT NOT NULL, -- See categories below
subcategory TEXT,
tags TEXT[] DEFAULT '{}', -- ["food", "nutrition", "ebt"]
-- Administering agency
agency_name TEXT NOT NULL,
agency_level TEXT NOT NULL, -- federal, state, county, city
agency_website TEXT,
agency_phone TEXT,
-- Geographic coverage
coverage_type TEXT NOT NULL, -- federal, state, county, city
coverage_states TEXT[] DEFAULT '{}', -- ["TX", "CA"] or ["*"] for all
coverage_fips TEXT[] DEFAULT '{}', -- County FIPS codes
-- Eligibility
eligibility_rules JSONB DEFAULT '[]',
eligibility_summary TEXT, -- Human-readable summary
income_limit_fpl_percent INTEGER, -- e.g., 130 for 130% FPL
income_limit_type TEXT, -- gross, net, modified_gross
asset_limit_cents INTEGER,
categorical_eligibility BOOLEAN DEFAULT false,
-- Benefit details
benefit_type TEXT NOT NULL, -- cash, voucher, service, tax_credit
benefit_value_cents INTEGER,
benefit_value_max_cents INTEGER,
benefit_frequency TEXT, -- monthly, annual, one_time
benefit_description TEXT,
-- Application process
application_url TEXT,
application_methods TEXT[] DEFAULT '{}', -- ["online", "in_person", "phone", "mail"]
processing_time_days INTEGER,
required_documents JSONB DEFAULT '[]',
how_to_apply JSONB DEFAULT '[]', -- Step-by-step instructions
-- Content
description TEXT NOT NULL,
short_description TEXT,
what_it_covers TEXT,
who_qualifies TEXT,
tips TEXT, -- Insider tips for applicants
-- Search
search_vector TSVECTOR, -- Full-text search
-- Metadata
source_url TEXT, -- Where we got this data
last_verified_at TIMESTAMPTZ,
is_active BOOLEAN DEFAULT true,
-- Timestamps
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- Indexes for performance
CREATE INDEX idx_programs_category ON programs(category);
CREATE INDEX idx_programs_coverage ON programs(coverage_type, coverage_states);
CREATE INDEX idx_programs_fips ON programs USING GIN(coverage_fips);
CREATE INDEX idx_programs_search ON programs USING GIN(search_vector);
CREATE INDEX idx_programs_active ON programs(is_active) WHERE is_active = true;
Program Categories
Programs are organized into categories that match how users think about their needs:const PROGRAM_CATEGORIES = {
food_assistance: {
name: "Food Assistance",
icon: "utensils",
programs: ["SNAP", "WIC", "School Meals", "Food Banks"]
},
healthcare: {
name: "Healthcare",
icon: "heart-pulse",
programs: ["Medicaid", "CHIP", "Medicare", "ACA Marketplace"]
},
housing: {
name: "Housing",
icon: "house",
programs: ["Section 8", "Public Housing", "LIHTC", "Rental Assistance"]
},
income_support: {
name: "Income Support",
icon: "hand-holding-dollar",
programs: ["TANF", "SSI", "SSDI", "Unemployment"]
},
childcare: {
name: "Childcare",
icon: "children",
programs: ["CCDF", "Head Start", "Pre-K"]
},
utilities: {
name: "Utilities",
icon: "bolt",
programs: ["LIHEAP", "Weatherization", "Lifeline"]
},
education: {
name: "Education",
icon: "graduation-cap",
programs: ["Pell Grant", "FAFSA", "Work-Study"]
},
tax_credits: {
name: "Tax Credits",
icon: "file-invoice-dollar",
programs: ["EITC", "CTC", "ACTC", "Savers Credit"]
},
veterans: {
name: "Veterans",
icon: "shield",
programs: ["VA Healthcare", "GI Bill", "VA Pension"]
},
disability: {
name: "Disability",
icon: "wheelchair",
programs: ["SSDI", "SSI", "Vocational Rehab"]
}
} as const;
Full-Text Search
Pathfinder uses PostgreSQL’s built-in full-text search with weighted rankings.Search Vector Setup
-- Auto-update search vector on insert/update
CREATE OR REPLACE FUNCTION update_program_search_vector()
RETURNS TRIGGER AS $$
BEGIN
NEW.search_vector :=
setweight(to_tsvector('english', COALESCE(NEW.name, '')), 'A') ||
setweight(to_tsvector('english', COALESCE(NEW.short_name, '')), 'A') ||
setweight(to_tsvector('english', COALESCE(NEW.agency_name, '')), 'B') ||
setweight(to_tsvector('english', COALESCE(NEW.short_description, '')), 'B') ||
setweight(to_tsvector('english', COALESCE(NEW.description, '')), 'C') ||
setweight(to_tsvector('english', COALESCE(array_to_string(NEW.tags, ' '), '')), 'C');
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER programs_search_vector_update
BEFORE INSERT OR UPDATE ON programs
FOR EACH ROW EXECUTE FUNCTION update_program_search_vector();
Search Query
// In programs.repository.ts
async function searchPrograms(query: string, options: SearchOptions) {
const { data } = await supabaseAdmin
.from('programs')
.select('*')
.textSearch('search_vector', query, {
type: 'websearch', // Supports "food assistance" AND queries
config: 'english'
})
.eq('is_active', true)
.limit(options.limit || 20);
return data;
}
websearchmode supports natural language queries- Weights prioritize name matches over description matches
- Tags enable synonym matching (e.g., “EBT” finds SNAP)
Geographic Filtering
Programs are filtered by geographic coverage at query time.Coverage Types
| Type | Example | Scope |
|---|---|---|
federal | SNAP | All states (coverage_states = ['*']) |
state | Texas Medicaid | Specific states (['TX']) |
county | Harris County Assistance | FIPS codes (['48201']) |
city | Austin Utility Rebate | FIPS + city filter |
Query Pattern
async function getProgramsByLocation(
state: string,
fips: string
): Promise<Program[]> {
const { data } = await supabaseAdmin
.from('programs')
.select('*')
.eq('is_active', true)
.or(`
coverage_type.eq.federal,
and(coverage_type.eq.state,coverage_states.cs.{${state}}),
and(coverage_type.eq.county,coverage_fips.cs.{${fips}}),
and(coverage_type.eq.city,coverage_fips.cs.{${fips}})
`);
return data;
}
FIPS Code Resolution
// geocoding.ts
interface GeocodedLocation {
lat: number;
lng: number;
state: string; // "TX"
county: string; // "Travis County"
fips: string; // "48453"
city?: string; // "Austin"
}
async function geocodeZip(zip: string): Promise<GeocodedLocation> {
// 1. Geocode ZIP to coordinates via Nominatim
// 2. Reverse geocode to get county boundary
// 3. Look up FIPS code from county name
}
Eligibility Rules Schema
Rules are stored as JSON for flexibility. The eligibility engine evaluates them at runtime.interface EligibilityRule {
// Rule identification
id: string;
description?: string;
// Condition
field: string; // Which screener field to check
operator: EligibilityOperator; // How to compare
value: RuleValue; // What to compare against
// Compound rules
conjunction?: "AND" | "OR";
children?: EligibilityRule[];
}
type EligibilityOperator =
| "equals"
| "not_equals"
| "greater_than"
| "less_than"
| "greater_than_or_equal"
| "less_than_or_equal"
| "in" // Value is in array
| "not_in"
| "contains" // Array contains value
| "less_than_fpl_percent" // Income below X% FPL
| "age_at_least"
| "age_under"
| "has_dependent_under"
| "is_citizen_or_qualified";
type RuleValue = string | number | boolean | string[];
Example: SNAP Rules
{
"eligibility_rules": [
{
"id": "income",
"description": "Gross income below 130% FPL",
"field": "household_income_monthly",
"operator": "less_than_fpl_percent",
"value": 130
},
{
"id": "citizenship",
"description": "Must be citizen or qualified immigrant",
"field": "citizenship_status",
"operator": "in",
"value": ["citizen", "qualified_alien", "refugee", "asylee"]
},
{
"id": "resources",
"description": "Resources below $2,500 (or $3,500 if elderly/disabled)",
"conjunction": "OR",
"children": [
{
"field": "countable_resources_cents",
"operator": "less_than_or_equal",
"value": 250000
},
{
"conjunction": "AND",
"children": [
{ "field": "has_elderly_or_disabled", "operator": "equals", "value": true },
{ "field": "countable_resources_cents", "operator": "less_than_or_equal", "value": 350000 }
]
}
]
}
]
}
Required Documents Schema
Each program specifies what documents are needed for application.interface DocumentRequirement {
type: DocumentType;
description: string;
required: boolean;
alternatives?: DocumentType[]; // Acceptable substitutes
notes?: string;
}
type DocumentType =
| "photo_id"
| "ssn_card"
| "birth_certificate"
| "proof_of_income"
| "pay_stubs"
| "tax_return"
| "bank_statement"
| "utility_bill"
| "lease_agreement"
| "proof_of_residency"
| "immigration_documents"
| "disability_determination"
| "medical_records"
| "school_enrollment"
| "other";
Example
{
"required_documents": [
{
"type": "photo_id",
"description": "Valid government-issued photo ID",
"required": true,
"alternatives": ["drivers_license", "passport", "state_id"],
"notes": "Must not be expired"
},
{
"type": "proof_of_income",
"description": "Income verification for all household members",
"required": true,
"alternatives": ["pay_stubs", "employer_letter", "tax_return"],
"notes": "Last 30 days of pay stubs or most recent tax return"
},
{
"type": "proof_of_residency",
"description": "Proof you live in the service area",
"required": true,
"alternatives": ["utility_bill", "lease_agreement", "bank_statement"],
"notes": "Must show current address, dated within 60 days"
}
]
}
Common Queries
Get Programs by Category
const { data } = await supabaseAdmin
.from('programs')
.select('id, name, short_name, short_description, benefit_value_cents')
.eq('category', 'food_assistance')
.eq('is_active', true)
.order('name');
Get Featured Programs (High-Value)
const { data } = await supabaseAdmin
.from('programs')
.select('*')
.eq('is_active', true)
.not('benefit_value_cents', 'is', null)
.gte('benefit_value_cents', 50000) // $500+/month
.order('benefit_value_cents', { ascending: false })
.limit(10);
Get Programs with Deadlines
const { data } = await supabaseAdmin
.from('programs')
.select('*')
.eq('is_active', true)
.not('application_deadline', 'is', null)
.gte('application_deadline', new Date().toISOString())
.order('application_deadline');
Data Sources
Programs data comes from multiple sources:| Source | Coverage | Update Frequency |
|---|---|---|
| Benefits.gov | Federal programs | Monthly |
| State HHS websites | State programs | Quarterly |
| 211 databases | Local programs | Varies |
| Manual research | Gap filling | Ongoing |
source_url and last_verified_at fields track data provenance.
Next Steps
Eligibility Engine
How programs are matched to users
Search Implementation
Full-text search and autocomplete