← Back Washlook →
Votern

Votern

Track voters and beneficiaries, coordinate staff and volunteers, watch spending, and get clear reports — built around how Philippine campaigns actually run on the ground.

Visit Live Site
Tanstack Start & AI Tanstack Start & AI
DeepSeek API DeepSeek API
Better Auth Better Auth
Resend Resend
Postgres Postgres
Redis Redis
BullMQ BullMQ
Dokploy Dokploy
Digital Ocean Digital Ocean
Cloudflare Cloudflare

Key Features

Deployment Process

Push / PR

GitHub

Run tests

CI test suite

Build image

Buildx · linux/amd64

Push image

Registry

Run migrations

Drizzle Kit

Trigger deploy

Dokploy webhook

Live app

Staging Production

Challenges & Solutions

Problem

The Areas page rolled up data across the full PSGC hierarchy (~42,010 barangays / ~43,768 nodes). Every request performed an access-scope tree walk and multiple unindexed GROUP BY queries, causing PostgreSQL CPU usage to spike to ~800% during repeated refreshes.

A materialized view didn't solve the issue because it required refreshing the entire dataset, making it inefficient for a multi-tenant system.

Solution

Replaced the live fan-out and materialized view with Redis caching + targeted invalidation in front of a single recursive CTE query:

  • Cached area metrics per organization, PSGC scope, and metric.
  • Cached member access scopes and PSGC descendants separately.
  • Invalidated only affected geographic ancestors instead of the entire organization.
  • Used BullMQ to proactively warm caches hourly.
  • Added manual refresh and post-deploy cache warming.
  • Added DB fallback when Redis is unavailable.

ResultRepeated requests now hit warm Redis caches instead of rebuilding the 42k-node tree, eliminating the PostgreSQL CPU spikes and keeping the Areas page consistently fast.

Gallery