Skip to content

feat: auto theme by local time, Redis HA, weekly digest email, campaign map - #1499

Merged
joelpeace48-cell merged 7 commits into
FinesseStudioLab:mainfrom
osasfaith:feat/stellar-wave-frontend-backend-features
Oct 20, 2026
Merged

joelpeace48-cell merged 7 commits into
FinesseStudioLab:mainfrom
osasfaith:feat/stellar-wave-frontend-backend-features

Conversation

@osasfaith

Copy link
Copy Markdown
Contributor

Closes #1355, Closes #1356, Closes #1357, Closes #1358

Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Refactoring (no functional or behavioral changes)
  • Performance improvement
  • Documentation update
  • Build / CI configuration change
  • Dependency update
  • Other:

Summary

Four features delivered in one PR:

  1. feat(frontend): Add light/dark mode auto-toggle based on local time #1358 — Auto theme by local time: Theme preference gains an auto mode that resolves to light between 06:00–18:00 local time and dark otherwise, re-evaluating every minute. Theme toggle cycles light → dark → auto.
  2. feat(backend): Redis cluster auto-failover configuration for high availability #1356 — Redis Sentinel/Cluster auto-failover: New createRedisClient factory selects standalone, Sentinel, or Cluster topology from env config (REDIS_SENTINEL_HOSTS, REDIS_SENTINEL_NAME, REDIS_CLUSTER_NODES), giving zero-downtime failover via ioredis.
  3. feat(backend): Automated campaign performance email digest for operators #1355 — Weekly campaign performance email digest: Pluggable email service (no-op without transport) plus a weekly digest job that aggregates 7-day participation analytics per campaign and emails operators. Idempotent per ISO week via checkpoint table.
  4. feat(frontend): Add interactive campaign map filtered by geographical regions #1357 — Interactive campaign map: CampaignMap SVG component renders participation hotspots sized by intensity with clickable region filters (North America, South America, Europe, Africa, Asia, Oceania). Mounted on the campaign analytics dashboard.

Motivation / Context

Closes #1355, Closes #1356, Closes #1357, Closes #1358

Changes

Area File(s) What
Theme frontend/src/theme.js, App.jsx Auto theme preference + time-based resolution
Redis HA backend/src/config/redis.js, index.js Sentinel/Cluster/standalone client factory
Email digest backend/src/services/emailService.js, jobs/weeklyDigestJob.js, index.js Weekly performance summary emails
Campaign map frontend/src/components/CampaignMap.jsx, CampaignAnalytics.jsx Interactive geo-filtered hotspot map

Testing

  • Frontend: 170/170 unit tests pass (npx vitest run) including 8 new theme tests and 5 new CampaignMap tests
  • Backend: 7/7 Redis config tests, 6/6 email + digest tests pass (node --test)
  • Pre-existing lint errors in CampaignAnalytics.jsx and sanitizer.js unchanged (verified via git stash)

Tradeoffs

  • Auto theme uses hour-window (06–18) rather than true sunrise/sunset — no geolocation dependency
  • Email digest recipients come from CAMPAIGN_DIGEST_RECIPIENTS env (no schema change for campaign creator emails)
  • CampaignMap is pure SVG (no map library) to avoid new dependencies

Out of scope

  • Actual SMTP transport wiring (email service is transport-injectable but ships as no-op)
  • Real geolocation data collection for participation regions
  • Campaign creator email storage / per-creator digest targeting

Introduce an 'auto' theme preference that resolves to light between
06:00-18:00 local time and dark otherwise, re-evaluating every minute.
Theme toggle now cycles light -> dark -> auto.
Introduce a createRedisClient factory that selects standalone, Sentinel,
or Cluster topology from environment configuration, giving zero-downtime
failover when a Redis node fails. Wire it into the server bootstrap.
Introduce a pluggable email service (no-op without transport) and a
weekly digest job that aggregates 7-day participation analytics per
campaign and emails operators. Idempotent per ISO week via checkpoints.
Introduce a CampaignMap component that renders participation hotspots
on an SVG world map, sized by intensity, with clickable region filters.
Mount it on the campaign analytics dashboard.
- Mock window.localStorage directly instead of Storage.prototype for
  reliable test isolation in jsdom
- Add injectable transport support to createEmailService factory
Convert gas_costs migration from knex-style to project-standard
export format so runMigrations works. Align theme storage-unavailable
test with getStoredTheme return contract.
@osasfaith
osasfaith force-pushed the feat/stellar-wave-frontend-backend-features branch from 771a313 to 5c877e6 Compare October 20, 2026 18:16
@joelpeace48-cell
joelpeace48-cell merged commit 6c5eeab into FinesseStudioLab:main Oct 20, 2026
9 of 28 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants