pablohernandezb/umbral-monitor

GitHub: pablohernandezb/umbral-monitor

一个开源政治分析平台,通过整合多维数据源监测委内瑞拉的政权转型与民主侵蚀动态。

Stars: 4 | Forks: 0

![Umbral](https://static.pigsec.cn/wp-content/uploads/repos/2026/03/2399e026d6154104.png) # Umbral 一个开源分析平台,用于监控委内瑞拉的政权转型动态。Umbral 通过实时数据、历史指数、精选新闻和专家情景分析来追踪民主侵蚀情况。 ## 功能特性 - **情景分析** — 五种基于证据的政权转型情景,由专家和公众按照李克特 1–5 级量表进行评级,并附有聚合概率指标 - **STAR 投票共识** — 使用 STAR 投票(评分然后自动决选)每日计算的专家和公众共识情景面板;作为每日快照存储在 Supabase 中 - **历史轨迹** — 涵盖 1900–2024 年的 V-Dem 风格民主指数图表 - **实时新闻源** — 聚合新闻,支持分类过滤、来源过滤、全文搜索以及针对每个情景的投票 - **政治犯追踪器** — 汇总拘留统计数据,包含按报告组织划分的人口统计细分 - **交互式时间线** — 民主事件数据集 (DEED),包含双语(西班牙语/英语)事件 - **阅览室** — 精选的书籍、文章、报告和新闻档案 - **事实核查源** — 来自三个委内瑞拉事实核查账户 ([@cazamosfakenews](https://x.com/cazamosfakenews), [@cotejoinfo](https://x.com/cotejoinfo), [@Factchequeado](https://x.com/Factchequeado)) 的推文,每日更新 - **GDELT 媒体信号** — 来自 GDELT 的每日存档不稳定指数、媒体基调 和文章数量,并带有注释的关键事件时间线 - **互联网连接监控(国家级)** — 针对委内瑞拉整体的、由 IODA 驱动的 BGP、主动探测 和网络望远镜 信号图表;每日 cron 任务将数据存档至 Supabase - **互联网连接监控(次国家级)** — 州级 IODA 仪表板,包含水平热力图、Leaflet 等值线图(25 个州 + 圭亚那埃塞奎博)和排名中断分数列表 - **预测市场** — 针对委内瑞拉相关市场的 Polymarket 合约仪表板 - **参与** — 供专家和公众提交情景概率评估的多步骤调查 - **双语** — 全面支持西班牙语/英语国际化 - **隐私优先分析** — 须经明确 Cookie 同意后方可启用的 GA4 集成 ## 技术栈 | 层级 | 技术 | |---|---| | 框架 | Next.js 15 (App Router) | | 语言 | TypeScript | | 样式 | Tailwind CSS, Framer Motion | | 数据库 | Supabase (PostgreSQL) 配合行级安全 (Row Level Security) | | 图表 | Recharts | | 地图 | Leaflet + react-leaflet 4.x (兼容 React 18) | | AI | Anthropic SDK (Claude Haiku 用于新闻翻译) | | 爬取 | RSS Parser (rss-parser) | | 图标 | Lucide React | ## 入门指南 ### 前置条件 - Node.js 18+ - npm - 一个 [Supabase](https://supabase.com) 项目(可选 — 如果没有,应用将使用本地模拟数据运行) ### 安装 ``` git clone https://github.com/pablohernandezb/umbral-project.git cd umbral-project npm install ``` ### 环境变量 在项目根目录创建一个 `.env.local` 文件。如果没有此文件,应用将使用本地样本数据在 **Mock Mode (模拟模式)** 下运行 — 无需数据库。 ``` # Supase (实时数据必需) NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key SUPABASE_SERVICE_ROLE_KEY=your-service-role-key # seed script only, never expose client-side # Google Analytics (可选) NEXT_PUBLIC_GA_ID=G-XXXXXXXXXX # Anthropic (可选,用于 AI 功能) ANTHROPIC_API_KEY=your-anthropic-key # X (Twitter) API — 事实核查 Feed 必需 (Basic plan bearer token) X_BEARER_TOKEN=your-x-bearer-token # Cron job 授权密钥 CRON_SECRET=your-cron-secret ``` ### 运行开发服务器 ``` npm run dev ``` 打开 [http://localhost:3000](http://localhost:3000)。 ## Mock Mode (模拟模式) vs. Supabase Mode (Supabase 模式) 应用会自动检测使用哪种模式: | 模式 | 条件 | 数据来源 | |---|---|---| | **Mock Mode (模拟模式)** | 没有有效的 `.env.local` | `data/mock.ts` (静态本地数据) | | **Supabase Mode (Supabase 模式)** | `.env.local` 中有有效的 Supabase 凭证 | 通过 Supabase 的 PostgreSQL | 通过添加或删除 `.env.local` 来切换模式,然后重启开发服务器。 在 Supabase 模式下,国家级 IODA 仪表板专门从数据库读取(由每日 cron 填充)。次国家级仪表板始终从 IODA 实时获取数据。 ## 数据库设置 如果您想连接真实的 Supabase 数据库: 1. **部署模式** — 将 `lib/supabase.ts` 中的 `SCHEMA_SQL` 导出内容复制到 Supabase SQL 编辑器中并运行 2. **配置凭证** — 将您的 Supabase URL 和密钥添加到 `.env.local` 3. **填充数据库** — 运行种子脚本: ``` npm run seed ``` 该模式创建了 16 个带有 RLS 策略的表。针对 `news_feed`、`political_prisoners` 和 `scenarios` 启用了实时订阅。 ## Cron Jobs (定时任务) 自动化数据收集运行在 Vercel 的调度器上(在 `vercel.json` 中配置)。所有任务通过使用并行获取来遵守 Vercel Hobby 版的 10 秒函数限制。 | 时间表 (UTC) | 端点 | 用途 | |---|---|---| | 每日 04:59 | `/api/gdelt?force=true` | 存档 GDELT 媒体信号(120 天滚动窗口) | | 每日 06:00 | `/api/ioda/sync` | 存档国家级 IODA 连接信号 + 事件 | | 每日 08:00 | `/api/ioda/sync-subnational` | 存档次国家级 IODA 区域信号 + 中断分数 | | 每日 10:00 | `/api/fact-check/refresh` | 获取 3 个事实核查账户的最新推文 | | 每日 12:00 | `/api/news/scrape` | 爬取并存储最新新闻文章 | | 每日 14:00 | `/api/analytics/snapshot` | 计算并存储 STAR 投票 + 提交平均值快照 | 您可以在开发期间手动触发任何 cron 任务: ``` # 在 macOS/Linux 上 curl "http://localhost:3000/api/analytics/snapshot?secret=" curl "http://localhost:3000/api/news/scrape?secret=" curl "http://localhost:3000/api/fact-check/refresh?secret=" curl "http://localhost:3000/api/gdelt?force=true" # 在 Windows PowerShell 上使用 curl.exe curl.exe "http://localhost:3000/api/analytics/snapshot?secret=" ``` ## 项目结构 ``` umbral-project/ ├── app/ # Next.js App Router pages and API routes │ ├── page.tsx # Landing page (Command Center) │ ├── about/ │ ├── how-did-we-get-here/ │ ├── news/ │ ├── participate/ │ ├── reading-room/ │ ├── privacy-terms/ │ ├── admin/ # Protected admin dashboard │ └── api/ │ ├── fact-check/refresh/ # Cron: X fact-checking tweets │ ├── gdelt/ # Cron + on-demand: GDELT media signals │ ├── ioda/ # IODA proxy + cron sync + batch endpoints │ │ ├── route.ts # Proxy to IODA API (never call IODA directly from client) │ │ ├── sync/ # Cron: archive national signals + events to Supabase │ │ ├── regions/ # Batch signals for all 25 VE regions │ │ └── outages/ # Batch outage scores for all 25 VE regions │ ├── news/scrape/ # Cron: news scraping │ └── analytics/snapshot/ # Cron: STAR voting + averages snapshots ├── components/ │ ├── layout/ # Header (with share menu), Footer │ ├── ui/ # ScenarioCard, NewsCard, GdeltDashboard, PolymarketDashboard, etc. │ ├── ioda/ # IODA connectivity dashboards (national + subnational) │ │ ├── IodaDashboard.tsx # National: 3 signal charts + outage events │ │ ├── SubnationalDashboard.tsx # State-level: heatmap + map + score list │ │ ├── StateHeatmap.tsx # Horizon heatmap (25 states × time) │ │ ├── VenezuelaMap.tsx # Leaflet choropleth (25 states + Esequibo) │ │ ├── OutageScoreList.tsx # Ranked outage scores │ │ ├── OutageEventList.tsx # Discrete outage events │ │ ├── SignalChart.tsx # Single-signal AreaChart card │ │ ├── StatusBadge.tsx # Connectivity status pill │ │ └── RegionSelector.tsx # Region dropdown │ ├── charts/ # TrajectoryChart, GdeltSignalChart │ ├── GoogleAnalytics.tsx │ ├── CookieBanner.tsx │ └── CookiePreferences.tsx ├── data/ │ ├── mock.ts # Local mock data for all tables │ ├── seed.ts # Database seed script │ ├── venezuela-states.ts # 25 VE states with IODA numeric codes (4482–4506) │ └── gdelt-annotations.ts # Key political events for GDELT chart overlay ├── hooks/ │ └── useIoda.ts # Generic IODA data-fetching hook with auto-refresh ├── i18n/ │ ├── es/common.json # Spanish translations (default) │ └── en/common.json # English translations ├── lib/ │ ├── supabase.ts # DB client, IS_MOCK_MODE flag, SCHEMA_SQL │ ├── data.ts # Data access layer with mock fallback │ ├── ioda.ts # IODA API functions, severity utilities, score computation │ ├── x-api.ts # X API client for fact-checking tweets │ └── cookie-consent.ts # Cookie consent context ├── public/data/ │ └── venezuela-geo.json # GADM 4.1 GeoJSON — 26 features, 319KB, full precision ├── types/ │ ├── index.ts # Core database TypeScript interfaces │ └── ioda.ts # IODA-specific types (signals, outages, severity, etc.) └── vercel.json # Cron job schedule ``` ## 常用命令 ``` npm run dev # Start development server npm run build # Production build (type-checks + optimizes) npm run start # Start production server npm run lint # ESLint npm run seed # Seed Supabase database ``` ## 国际化 应用默认为西班牙语并支持英语。通过页眉切换语言。所有翻译字符串位于 `i18n/es/common.json` 和 `i18n/en/common.json` 中,并使用点表示法 通过 `useTranslation()` hook 访问: ``` const { t } = useTranslation() t('scenarios.democraticTransition.title') t('ioda.status.outage') t('ioda.events.detected', { count: 4 }) ``` ## 贡献 欢迎贡献。请在提交 Pull Request 之前开启一个 issue 来讨论建议的更改。 1. Fork 本仓库 2. 创建一个功能分支 (`git checkout -b feature/your-feature`) 3. 提交您的更改 4. 推送到分支并开启一个 Pull Request ## 许可证 [Apache License 2.0](LICENSE)
标签:BGP, ESC4, GDELT, IODA, Leaflet, OSINT, Polymarket, PostgreSQL, React, STAR投票, Supabase, Syscalls, V-Dem, 事实核查, 互联网连接监控, 交互式时间轴, 代码示例, 仪表盘, 信息聚合, 公共数据, 历史指数, 双语支持, 地图可视化, 场景分析, 委内瑞拉, 媒体信号, 实时新闻, 政权转型, 政治犯追踪, 政治监控, 数据分析, 数据泄露防护, 民主测评, 社会动态, 索引导航, 网络中断检测, 网络探测, 自动化攻击, 英语, 西班牙语, 选举共识, 预测市场