Skip to content

Comments

Add Global Giving Activity Index with multi-platform aggregation#255

Merged
SebastienMelki merged 15 commits intofeat/happy-monitorfrom
claude/review-pr-zPvM9
Feb 23, 2026
Merged

Add Global Giving Activity Index with multi-platform aggregation#255
SebastienMelki merged 15 commits intofeat/happy-monitorfrom
claude/review-pr-zPvM9

Conversation

@koala73
Copy link
Owner

@koala73 koala73 commented Feb 23, 2026

Summary

Adds a new Global Giving Activity Index panel that aggregates personal charitable giving data from multiple crowdfunding and institutional sources into a composite activity metric. The implementation includes:

  • GetGivingSummary RPC that samples campaigns from GoFundMe, GlobalGiving, and JustGiving APIs
  • Campaign sampling & velocity estimation from live platform data with directional daily flow extrapolation
  • Category breakdown of giving activity (Medical, Disaster Relief, Education, etc.)
  • Crypto philanthropy tracking via on-chain wallet monitoring (Endaoment, The Giving Block)
  • Institutional baseline from OECD ODA and CAF World Giving Index data
  • Activity Index (0-100) computed from platform volume, donation velocity, and new campaign signals
  • GivingPanel UI component with tabbed interface for platforms, categories, crypto, and institutional data
  • Redis caching (1-hour TTL) for campaign data that shifts slowly

Type of change

  • New feature
  • New data source / feed
  • API endpoints (/api/*)

Affected areas

  • News panels / RSS feeds
  • API endpoints (/api/*)
  • Config / Settings

Implementation details

Backend (server/worldmonitor/giving/v1/get-giving-summary.ts):

  • Samples ~120 campaigns across 6 categories from GoFundMe public API
  • Extrapolates daily volume using campaign age and donation counts
  • Fetches GlobalGiving project stats and applies directional estimates
  • Uses published JustGiving annual reports ($7B+) for macro signal
  • Estimates crypto giving at ~$5.5M/day from on-chain tracking data
  • Computes composite activity index weighted by data quality and signal strength
  • Caches results in Redis for 1 hour

Frontend (src/components/GivingPanel.ts):

  • Displays activity index with color-coded severity (0-100 scale)
  • Shows trend direction (rising/stable/falling) with visual indicators
  • Tabbed interface for platforms, categories, crypto, and institutional data
  • Platform table with daily volume, donation velocity, and data freshness badges
  • Category breakdown with share percentages and trending indicators
  • Crypto section showing daily inflow, tracked wallets, and top receivers
  • Institutional section with OECD ODA and CAF World Giving Index metrics

Proto definitions (proto/worldmonitor/giving/v1/):

  • service.proto: GivingService RPC definition
  • giving.proto: Message types for summary, platforms, categories, crypto, and institutional data
  • get_giving_summary.proto: Request/response types with optional limits

Generated code:

  • Server-side handler types and route creation
  • Client-side service client with circuit breaker integration
  • TypeScript interfaces for all data structures

Checklist

  • Tested on worldmonitor.app variant
  • No API keys or secrets committed (uses public APIs)
  • TypeScript compiles without errors
  • Proto definitions follow existing patterns
  • Circuit breaker and error handling implemented
  • Redis caching configured with appropriate TTL

Notes

  • Campaign sampling is best-effort per category; failures are gracefully handled
  • Daily volume estimates are directional proxies, not precise measurements
  • Crypto giving percentage (~0.8% of total) based on 2024 industry estimates
  • Activity index baseline is 50; adjusted ±20 based on volume ratio, velocity, and new campaigns
  • Data freshness varies by source: "live" (GoFundMe), "weekly" (GlobalGiving), "annual" (JustGiving, OECD)

https://claude.ai/code/session_01MTSaVy4aB4xLgB9qa5Uayp

SebastienMelki and others added 15 commits February 22, 2026 16:26
…ty) (#226)

* docs: add community guidelines — contributing guide, code of conduct, and security policy

Add three community health files for the open-source project:

- CONTRIBUTING.md: comprehensive guide covering architecture overview (sebuf,
  variants, directory structure), development setup with make commands,
  AI-assisted development policy, sebuf RPC workflow, data source and RSS
  feed contribution guides, coding standards, and PR process
- CODE_OF_CONDUCT.md: Contributor Covenant v2.1 adapted for World Monitor
- SECURITY.md: responsible disclosure policy, security considerations for
  edge functions/sebuf handlers, and contributor best practices

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: add missing blank line before list in CONTRIBUTING.md (MD032)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: expand AI section with LLM label attribution and rationale

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: remove GitHub link from AI section

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: simplify AI section back to concise version with PR labels

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* chore: apply cargo fmt formatting to main.rs

Pure formatting normalization with no logic changes. Separated from
the behavioral fix to keep git blame clean.

https://claude.ai/code/session_01RPQ1PEqxTSEG6rB5XadzEz

* fix: restrict settings-window re-focus to macOS to avoid Windows focus churn

On Windows, the Focused(true) handler on the main window calls
show()+set_focus() on the settings window, which steals focus back,
retriggering the event in a tight loop and presenting as a UI hang.

Gate the match arm with #[cfg(target_os = "macos")] (compile-time
attribute) instead of cfg!() (runtime macro) to match the convention
used by the adjacent macOS-only handlers and eliminate dead code on
non-macOS builds entirely.

https://claude.ai/code/session_01RPQ1PEqxTSEG6rB5XadzEz

---------

Co-authored-by: Claude <noreply@anthropic.com>
)

* fix(sentry): add noise filters for 5 non-actionable error patterns

Filter dynamic import alt phrasing, script parse errors, maplibre
style/WebGL crashes, and CustomEvent promise rejections. Also fix
beforeSend to catch short Firefox null messages like "E is null".

* fix: cache write race, settings stale key status, yahoo gate concurrency

P1: Replace async background thread cache write with synchronous fs::write
to prevent out-of-order writes and dirty flag cleared before persistence.

P2: Add WorldMonitorTab.refresh() called after loadDesktopSecrets() so
the API key badge reflects actual keychain state.

P3: Replace timestamp-based Yahoo gate with promise queue to ensure
sequential execution under concurrent callers.

* feat: add Upstash Redis shared caching to all RPC handlers + fix cache key contamination

- Add Redis L2 cache (getCachedJson/setCachedJson) to 28 RPC handlers
  across all service domains (market, conflict, cyber, economic, etc.)
- Fix 10 P1 cache key contamination bugs where under-specified keys
  caused cross-request data pollution (e.g. filtered requests returning
  unfiltered cached data)
- Restructure list-internet-outages to cache-then-filter pattern so
  country/timeRange filters always apply after cache read
- Add write_lock mutex to PersistentCache in main.rs to prevent
  desktop cache write-race conditions
- Document FMP (Financial Modeling Prep) as Yahoo Finance fallback TODO
  in market/v1/_shared.ts

* fix: cache-key contamination and PizzINT/GDELT partial-failure regression

- tech-events: fetch with limit=0 and cache full result, apply limit
  slice after cache read to prevent low-limit requests poisoning cache
- pizzint: restore try-catch around PizzINT fetch so GDELT tension
  pairs are still returned when PizzINT API is down

* fix: remove extra closing brace in pizzint try-catch

* fix: recompute conferenceCount/mappableCount after limit slice

* fix: bypass WM API key gate for registration endpoint

/api/register-interest must reach cloud without a WorldMonitor API key,
otherwise desktop users can never register (circular dependency).
* fix: resolve AppImage blank white screen and font crash on Linux (#238)

Disable WebKitGTK DMA-BUF renderer by default on Linux to prevent blank
white screens caused by GPU buffer allocation failures (common with
NVIDIA drivers and immutable distros like Bazzite). Add Linux-native
monospace font fallbacks (DejaVu Sans Mono, Liberation Mono) to all font
stacks so WebKitGTK font resolution doesn't hit out-of-bounds vector
access when macOS-only fonts (SF Mono, Monaco) are unavailable.

https://claude.ai/code/session_01TF2NPgSSjgenmLT2XuR5b9

* fix: consolidate monospace font stacks into --font-mono variable

- Define --font-mono in :root (main.css) and .settings-shell (settings-window.css)
- Align font stack: SF Mono, Monaco, Cascadia Code, Fira Code, DejaVu Sans Mono, Liberation Mono
- Replace 3 hardcoded JetBrains Mono stacks with var(--font-mono)
- Replace 4 hardcoded settings-window stacks with var(--font-mono)
- Fix pre-existing bug: var(--font-mono) used in 4 places but never defined
- Match index.html skeleton font stack to --font-mono

---------

Co-authored-by: Claude <noreply@anthropic.com>
* feat: make intelligence alert popup opt-in via dropdown toggle

Auto-popup was interrupting users every 10s refresh cycle. Badge still
counts and pulses silently. New toggle in dropdown (default OFF) lets
users explicitly opt in to auto-popup behavior.

* chore: bump version to 2.5.5

## Changelog

### Features
- Intelligence alert popup is now opt-in (default OFF) — badge counts silently, toggle in dropdown to enable auto-popup

### Bug Fixes
- Linux: disable DMA-BUF renderer on WebKitGTK to prevent blank white screen (NVIDIA/immutable distros)
- Linux: add DejaVu Sans Mono + Liberation Mono font fallbacks for monospace rendering
- Consolidate monospace font stacks into --font-mono CSS variable (fixes undefined var bug)
- Reduce dedup coordinate rounding from 0.5° to 0.1° (~10km precision)
- Vercel build: handle missing previous deploy SHA
- Panel base class: add missing showRetrying method
- Vercel ignoreCommand shortened to fit 256-char limit

### Infrastructure
- Upstash Redis shared caching for all RPC handlers + cache key contamination fix
- Format Rust code and fix Windows focus handling

### Docs
- Community guidelines: contributing, code of conduct, security policy
- Updated .env.example

* chore: track Cargo.lock for reproducible Rust builds

* fix: update layer help popup with all current map layers

Added missing layers to the ? help popup across all 3 variants:
- Full: UCDP Events, Displacement, Spaceports, Cyber Threats, Fires,
  Climate Anomalies, Critical Minerals; renamed Shipping→Ship Traffic
- Tech: Tech Events, Cyber Threats, Fires
- Finance: GCC Investments

* docs: update README with crypto prices, analytics, typography, and dedup grid fix

* fix: add /ingest to service worker NetworkOnly routes

The SW was intercepting PostHog /ingest/* requests and returning
no-response (404) because no cache match existed. Adding NetworkOnly
ensures analytics requests pass through to Vercel's rewrite proxy.

* chore: update Cargo.lock for v2.5.5

* fix: use explicit colors for findings toggle switch visibility
vi → vn (ISO 3166-1 alpha-2 for Vietnam). Also add explicit th mapping for Thailand.
- Fix PostHog /ingest 404: Workbox registerRoute defaults to GET only,
  PostHog sends POST. Add POST routes for /api/ and /ingest/.
- Fix fullscreen crash: optional chaining on exitFullscreen()?.catch()
  for browsers returning undefined instead of Promise.
- Add 6 noise filters: __firefox__, ifameElement.contentDocument,
  Invalid video id, Fetch is aborted, Stylesheet append timeout,
  Cannot assign to read only property.
- Widen Program failed to link filter (remove ": null" suffix).
The broad regex /^https?:\/\/.*\/api\/.*/i matched ANY URL with /api/
in the path, including external APIs like NASA EONET
(eonet.gsfc.nasa.gov/api/v3/events). Workbox intercepted these
cross-origin requests with NetworkOnly, causing no-response errors
when CORS failed.

Changed all /api/, /ingest/, and /rss/ SW route patterns to use
sameOrigin callback check so only our Vercel routes get NetworkOnly
handling. External APIs now pass through without SW interference.
- Narrow /telegram route to exact prefix match (prevents /telegramXYZ matching)
- Remove lastError from public /telegram/feed and /health responses
- Remove relayUrl and internal details from Vercel proxy error responses
- Replace O(n^2) findIndex dedup with Set-based dedup
- Remove unused writeFileSync/existsSync imports
- Log top-level poll errors instead of swallowing silently
- Warn when selected channel bucket is empty

https://claude.ai/code/session_01MMR4VPJDcAW5PuhLu3Vt1b
@vercel
Copy link

vercel bot commented Feb 23, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
worldmonitor Ready Ready Preview, Comment Feb 23, 2026 1:23pm
worldmonitor-finance Ready Ready Preview, Comment Feb 23, 2026 1:23pm
worldmonitor-happy Ready Ready Preview, Comment Feb 23, 2026 1:23pm
worldmonitor-startup Ready Ready Preview, Comment Feb 23, 2026 1:23pm

Request Review

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4cb58901f4

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

])
.setup(|app| {
// Load persistent cache into memory (avoids 14MB file I/O on every IPC call)
let cache_path = cache_file_path(&app.handle()).unwrap_or_default();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Propagate cache path resolution failures

Using unwrap_or_default() here hides app_data_dir failures and initializes PersistentCache with an empty path, so read_cache_entry later returns Ok(None) instead of surfacing an error. In that failure mode, the frontend read path in getPersistentCache treats desktop cache reads as successful misses and does not fall back to IndexedDB/localStorage, while writes still fail and fall back, leading to inconsistent cache behavior and lost persisted reads across restarts on environments where app data dir resolution fails.

Useful? React with 👍 / 👎.

@SebastienMelki
Copy link
Collaborator

Thanks a lot @koala73

@SebastienMelki SebastienMelki merged commit 43effb6 into feat/happy-monitor Feb 23, 2026
6 checks passed
SebastienMelki added a commit that referenced this pull request Feb 24, 2026
Cherry-pick the giving feature that was left behind when PR #255
batch-merged without including #254's proto/handler/panel files.

Adds:
- Proto definitions (GivingService, GivingSummary, PlatformGiving, etc.)
- Server handler: GoFundMe/GlobalGiving/JustGiving/crypto/OECD aggregation
- Client service with circuit breaker
- GivingPanel with tabs (platforms, categories, crypto, institutional)
- Full wiring: API routes, vite dev server, data freshness, panel config
- Happy variant panel config entry

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants