mirror of
https://github.com/koala73/worldmonitor.git
synced 2026-05-05 06:41:59 +02:00
2f5445284b6e62493c8d2e1b31f95b57c283f1fd
20 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
99b536bfb4 |
docs(energy): /corrections revision-log page (Week 4 launch requirement) (#3323)
* docs(energy): /corrections revision-log page (Week 4 launch requirement)
All five methodology pages reference /corrections (the auto-revision-log
URL promised in the Global Energy Flow parity plan §20) but the page
didn't exist — clicks 404'd. This lands the page.
Content:
- Explains the revision-log shape: `{date, assetOrEventId, fieldChanged,
previousValue, newValue, trigger, sourcesUsed, classifierVersion}`.
- Defines the trigger vocabulary (classifier / source / decay / override)
so readers know what kind of change they're seeing.
- States the v1-launch truth honestly: the log is empty at launch and
fills as the post-launch classifier pass (in proactive-intelligence.mjs)
runs on its normal schedule. No fake entries, no placeholder rows.
- Documents the correction-submission path (operators / regulators /
researchers with public source URLs) and the contract that
corrections write `override`-trigger entries citing the submitted
source — not anonymous overrides.
- Cross-links all five methodology pages.
- Explains WHY we publish this: evidence-first classification only
works if the audit trail is public; otherwise "the classifier said
so" has no more authority than any other opaque pipeline.
Also fixes a navigation gap: docs/docs.json was missing both
methodology/disruptions (landed in PR #3294 but never registered in
nav) and the new corrections page. Both now appear in the "Intelligence
& Analysis" group alongside the other methodology pages.
No code changes. MDX lint + docs.json JSON validation pass.
* docs(energy): reframe /corrections as planned-surface spec (P1 review fix)
Greptile P1: the prior /corrections page made live-product claims
("writes an append-only entry here", "expect the first entries within
days", "email corrections@worldmonitor.app") that the code doesn't
back. The revision-log writer ships with the post-launch classifier;
the correction-intake pipeline does not yet exist; and the related
detail handlers still return empty `revisions` arrays with code
comments explicitly marking the surface as future work.
Fix: rewrite the page as a planned-surface specification with a
prominent Status callout. Changes:
- Page title: "Revision Log" → "Revision Log (Planned)"
- Prominent <Note> callout at the top states v1 launch truth: log is
not yet live, RPC `revisions` arrays are empty by design,
corrections are handled manually today.
- "Current state (v1 launch)" section removed; replaced with two
explicit sections: "What IS live today" (evidence bundles,
methodology, versioned classifier output) and "What is NOT live
today" (log entries, automated correction intake, override-writer).
- "Within days" timeline language removed — no false operational SLA.
- Email submission path removed (no automated intake exists). Points
readers to GitHub issues for manual review today.
- Preserves the planned data shape, trigger vocabulary, policy
commitment, and "why we publish this" framing — those are spec, not
claims.
Also softens /corrections references in the four methodology pages
(pipelines, storage, shortages, disruptions) so none of them claim
the revision log is live. Each now says "planned revision-log shape
and submission policy" and points manual corrections at GitHub issues.
MDX lint 122/122 clean. docs.json JSON validation clean. No code
changes; pure reframing to match reality.
* docs(shortages): fix P1 overclaim + wrong RPC name (round-2 review)
Two findings on the same file:
P1 — `energy_asset_overrides` table documented as existing. It doesn't.
The PR's corrections.mdx explicitly lists the override-writer as NOT
live in v1; this section contradicted that. Rewrote as "Break-glass
overrides (planned)" with a clear Status callout matching the pattern
established in docs/corrections.mdx and the other methodology pages.
Points readers at GitHub issues for manual corrections today.
P2 — Wrong RPC name: `listActiveFuelShortages` doesn't exist. The
shipped RPC (in proto/worldmonitor/supply_chain/v1/
list_fuel_shortages.proto + server/worldmonitor/supply-chain/v1/
list-fuel-shortages.ts) is `ListFuelShortages`. Replaced the name +
reframed the sentence to describe what the actual RPC already exposes
(every FuelShortageEntry includes evidence.evidenceSources[]) rather
than projecting a future surface.
Also swept the other methodology pages for the same class of bug:
- grep for _overrides: only the one line above
- grep for listActive/ getActive RPC names: none found
- verified all RPC mentions in docs/methodology + docs/corrections.mdx
match names actually in proto (ListPipelines, ListStorageFacilities,
ListFuelShortages, ListEnergyDisruptions, GetPipelineDetail,
GetStorageFacilityDetail, GetFuelShortageDetail)
MDX lint clean. No code changes.
* docs(methodology): round-3 sibling sweep for revision-log overclaims
Reviewer (Greptile) caught a third round of the same overclaim pattern
I've been trying to stamp out: docs/methodology/shortages.mdx line 46
said "Stale shortages never persist silently. Every demotion writes to
the public revision log." — contradicting the same PR's /corrections
page which explicitly frames the revision log as not-yet-live. Fixed
that one AND did the mechanical sibling sweep the review pattern
clearly called for.
Changes:
- `docs/methodology/shortages.mdx:46` — rewrote the auto-decay footer
to future tense: "When the post-launch classifier ships, stale
shortages will never persist silently — every demotion will write
an entry to the planned public revision log." Points readers at
/corrections for the designed shape. Notes that today the demotion
thresholds ARE the contract; the structured audit trail is what
lands with the classifier.
- `docs/methodology/chokepoints.mdx:64` — sibling sweep caught the
same bug class ("Every badge transition writes to the public
revision log"). Reworded to future tense and pointed manual
corrections at GitHub issues, matching the pattern already applied
to pipelines / storage / shortages in prior commits on this PR.
Final audit of remaining revision-log mentions across all 5
methodology pages + corrections.mdx — every one uses hedged tense now
("planned", "will", "when live", "designed", "not yet live", "once
the classifier ships"). The one remaining present-tense "emit" in
shortages.mdx:77 is inside the "(planned)" break-glass section with
its own Status callout, so it's correctly scoped.
Following the plan-doc-as-docs-source-overclaim skill's step-4
(sibling sweep) explicitly this time — which also retroactively
validates the skill extraction: three review rounds was the cost of
not running the sweep on round 1.
MDX lint clean. No code changes.
* docs(corrections): drop hardcoded launch date (Greptile P2)
Greptile inline P2 at docs/corrections.mdx:60: the phrase
"v1 launch (2026-04-23)" pins a specific calendar date that will read
inaccurately to visitors months later once entries start appearing.
Dropped the parenthetical date. "Status — v1 launch:" keeps the
scoping clear without tying it to a specific day. When live entries
start appearing on this page (or when the page is rewritten to show
real rows), a "last updated" marker will replace the status callout
entirely — no migration churn needed.
MDX lint 122/122 clean.
|
||
|
|
a17a3383d9 |
feat(variant): Energy Atlas — Release 1 Day 1 (variant scaffolding) (#3291)
* feat(variant): add energy variant scaffolding for energy.worldmonitor.app Release 1 Day 1 of the Energy Atlas plan — introduces src/config/variants/energy.ts modeled on the commodity variant. No new panels or RPCs yet; the variant reuses existing energy-related panels (energy-complex, oil-inventories, hormuz, energy-crisis, fuel-prices, renewable-energy) + supply-chain/sanctions context. Map layers enable pipelines, waterways, AIS, commodityPorts, minerals, climate, outages, natural, weather. All geopolitical/military/tech/finance/happy variant layers explicitly disabled per variant isolation conventions. Next PRs on feat/energy-atlas-release-1 add: - Pipeline & storage registries (curated critical assets, ~75 gas / ~75 oil / ~125 storage) - Global fuel-shortage registry with automated evidence-threshold promotion - Pipeline/storage disruption event log - Country drill-down Energy section - Atlas landing composition at variant root * feat(variant): wire energy variant into runtime + atlas landing composition Day 2 of the Energy Atlas Release 1 plan. The Day-1 commit added a canonical variants/energy.ts but discovery during Day 2 showed the app's runtime variant resolution lives in src/config/panels.ts (ENERGY_PANELS/ENERGY_MAP_LAYERS/etc.), not in variants/*.ts (which are orphans). This commit does the real wiring. Changes: - src/config/panels.ts — ENERGY_PANELS, ENERGY_MAP_LAYERS, ENERGY_MOBILE_MAP_LAYERS; registered in ALL_PANELS, VARIANT_DEFAULTS, VARIANT_PANEL_OVERRIDES; wired into DEFAULT_MAP_LAYERS + MOBILE_DEFAULT_MAP_LAYERS ternaries. Panels at launch: map, live-news, insights, energy-complex, oil-inventories, hormuz, energy-crisis, fuel-prices, renewable-energy, commodities, energy (news), macro-signals, supply-chain, sanctions-pressure, gulf-economies, gcc-investments, climate, monitors, world-clock, latest-brief. - src/config/variant.ts — recognize 'energy' as allowed SITE_VARIANT; resolve energy.worldmonitor.app subdomain to 'energy'; honor localStorage override. - src/config/variant-meta.ts — SEO entry for energy.worldmonitor.app (title, description, keywords targeting 'oil pipeline tracker', 'gas storage map', 'fuel shortage tracker', 'chokepoint monitor', etc.). - src/app/panel-layout.ts — desktop variant switcher + mobile menu both list energy with ⚡ icon and t('header.energy') label. - src/App.ts + src/app/data-loader.ts — energy variant enables trade-policy and supply-chain data loads (chokepoint exposure is a core Atlas surface). - src/app/data-loader.ts — daily-brief newsCategories override for energy variant (energy, energy-markets, oil-gas-news, pipeline-news, lng-news). - src/locales/en.json — 'header.energy' translation key. - src/config/variants/energy.ts — add clarifying comment that real wiring lives in panels.ts (same orphan pattern as commodity.ts/finance.ts/etc.). Atlas landing composition: the variant now renders its energy panel set with energy-specific names (Energy Atlas Map, Energy Headlines, AI Energy Insights) when SITE_VARIANT === 'energy'. Pipeline and commodity-port map layers enabled so Week 2's pipeline registry + storage-facility registry drop in with layers already toggled on. Typecheck clean; 175 pre-push tests expected to remain green. Subsequent PRs on feat/energy-atlas-release-1: - Week 2: pipeline registry + storage facility registry (evidence-based) - Week 3: fuel-shortage classifier + disruption log + country drill-down - Week 4: automated revision log, SEO polish, launch * feat(energy): chokepoint strip at top of atlas (7 chokepoints) Day 3 of the Energy Atlas Release 1 plan. Adds ChokepointStripPanel — a compact horizontal strip of chip-style cards, one per chokepoint, showing name + status color + flow-as-%-of-baseline + active-warnings badge. Ordered by volume: Hormuz, Malacca, Suez, Bab el-Mandeb, Turkish Straits, Danish Straits, Panama. GEF covers 5 chokepoints (Hormuz, Malacca, Suez, Bab el-Mandeb, Panama). We cover 7 — adds Turkish Straits + Danish Straits. One of the surpass vectors enumerated in §5.7 of the plan doc. Data: reuses the existing fetchChokepointStatus() RPC backed by supply_chain:chokepoints:v4 (Portwatch DWT + AIS calibration). No new backend work; this is pure UI composition. Changes: - src/components/ChokepointStripPanel.ts — new Panel subclass with in-line CSS for the chip strip; falls back gracefully when a chokepoint is missing from the response or FlowEstimate is absent. - src/components/index.ts — barrel export. - src/app/panel-layout.ts — import + createPanel registration near existing energy panels. - src/config/panels.ts — ENERGY_PANELS adds 'chokepoint-strip' at priority 1 (renders near top of atlas). Also fixes two panel-ID mismatches caught while wiring: 'hormuz' → 'hormuz-tracker' and 'renewable-energy' → 'renewable' (matches HormuzPanel.ts and RenewableEnergyPanel registration). Typecheck clean. No new tests required — panel renders real data. * feat(energy): attribution footer utility + methodology page stubs Days 4 & 5 of the Energy Atlas Release 1 plan. ## Day 4 — Attribution footer (src/utils/attribution-footer.ts) A reusable string-builder that stamps every energy-atlas number with its provenance. Design intent per plan §5.6 (quantitative rigour moat): "every flow number carries {value, baseline, n_vessels, methodology, confidence}". Input schema: - sourceType: operator | regulator | ais | satellite | press | classifier | derived - method: short free-text ("AIS-DWT calibrated", "GIE AGSI+ daily") - sampleSize + sampleLabel: observation count and unit - updatedAt: ISO8601 / Date / number — rendered as "Xm/h/d ago" - confidence: 0..1 — bucketed to high/medium/low - classifierVersion: surfaced when evidence-derived badges ship in Week 2+ - creditName / creditUrl: CC-BY / dataset credit (OWID, GEM pattern) Every field also writes data-attributes (data-attr-source, data-attr-n, data-attr-confidence, data-attr-classifier) so MCP / scraper / analyst agents can extract the same provenance the reader sees. Agent-native by default. Applied to ChokepointStripPanel — the panel now shows its evidence footer ("AIS calibration · Portwatch DWT + AIS · N AIS disruption signals · updated Xh ago · EIA World Oil Transit Chokepoints"). Future pipeline / storage / shortage panels drop the same helper in and hit the same rigour bar automatically. 7 unit tests (tests/attribution-footer.test.mts, node:test via tsx): minimal footer, method + sample size + credit, "X ago" formatting, confidence band mapping, full data-attribute emission, credit omission, HTML escaping. ## Day 5 — Public methodology page stubs (docs/methodology/) Four new MDX pages surfaced in docs/docs.json navigation under "Intelligence & Analysis": - chokepoints.mdx — 7 chokepoints, Portwatch+AIS calibration method, status badge derivation, known limits, revision-log link. - pipelines.mdx — curated critical-asset scope, GEM CC-BY attribution, evidence-schema (NOT conclusion labels), freshness SLA, corrections. - storage.mdx — curated ~125 facilities scope, "published not synthesized" fill % policy, country-aggregate fallback, attribution. - shortages.mdx — automated tiered evidence threshold, LLM second-pass gating, auto-decay cadence, evidence-source transparency, break-glass override policy (admin-only, off critical path). All four explicitly document WorldMonitor's automated-data-quality posture: no human review queues, quality via classifier rigour + evidence transparency + auto-decay + public revision log. Typecheck clean. attribution-footer.test.mts passes all 7 tests. * fix(variant): close three energy-variant isolation leaks from review Addresses three High findings from PR review: 1. Map-layer isolation (src/config/map-layer-definitions.ts) - Add 'energy' to the MapVariant type union. - Add energy entry to VARIANT_LAYER_ORDER with the curated energy subset (pipelines, waterways, commodityPorts, commodityHubs, ais, tradeRoutes, minerals, sanctions, fires, climate, weather, outages, natural, resilienceScore, dayNight). Without this, getLayersForVariant() and sanitizeLayersForVariant() (called from DeckGLMap and App.ts) fell back to VARIANT_LAYER_ORDER.full, letting the full geopolitical palette (military, nuclear, iranAttacks, conflicts, hotspots, bases, protests, flights, ucdpEvents, displacement, gpsJamming, satellites, ciiChoropleth, cables, datacenters, economic, cyberThreats, spaceports, irradiators, radiationWatch) into the desktop map tray and saved/URL layer sanitization — breaking the PR's stated no-geopolitical-bleed goal and violating multi-variant-site-data-isolation. 2. News feeds (src/config/feeds.ts + src/app/data-loader.ts) - Add ENERGY_FEEDS with three keys matching ENERGY_PANELS: live-news (broad energy headlines from OilPrice, Rigzone, Reuters/Bloomberg/FT energy), energy (OPEC + crude + NatGas/LNG + pipelines/chokepoints + crisis/shortages + refineries), supply-chain (tanker/shipping, chokepoints, energy sanctions, ports/terminals). - Add SITE_VARIANT === 'energy' branch to the FEEDS variant selector. - Correct newsCategories override in data-loader.ts — my earlier speculative values ['energy','energy-markets','oil-gas-news', 'pipeline-news','lng-news'] included keys that did not exist in any feed map. Replaced with real ENERGY_FEEDS keys ['live-news', 'energy', 'supply-chain']. Without this, FEEDS resolved to FULL_FEEDS for the energy variant — live-news + daily-brief both ingested the world/geopolitical feed set. 3. Insights / AI brief framing (src/components/InsightsPanel.ts) - Add SITE_VARIANT === 'energy' branch to geoContext: dedicated energy prompt focused on physical supply (pipelines, chokepoints, storage, days-of-cover, refineries, LNG, sanctions, shortages) with evidence-grounded attribution, no bare conclusions. - Add '⚡ ENERGY BRIEF' heading branch in renderWorldBrief(). Without this, the renamed 'AI Energy Insights' panel fell through to the empty default prompt and rendered 'WORLD BRIEF'. Typecheck clean. attribution-footer tests still pass (no coupling changed). * fix(variant): close energy-variant leak in SVG/mobile fallback map Fifth High finding from PR review: src/components/Map.ts createLayerToggles() (line 381-409) has no 'energy' branch in its variant ternary, so energy-variant users whose MapContainer routes to the SVG/mobile fallback (no WebGL, mobile with deviceMemory < 3, or DeckGL init throws) see the full geopolitical toggle set — iranAttacks, conflicts, hotspots, bases, nuclear, irradiators, military, protests, flights, gpsJamming, ciiChoropleth, cables, datacenters. Clicking any toggle flips the layer via toggleLayer() which is variant-blind (Map.ts:3383) — so users could enable military / nuclear layers on the energy variant despite the rest of the isolation work in panels.ts, map-layer-definitions.ts, feeds.ts, and InsightsPanel.ts. Fix: add energyLayers array with the SVG-capable subset of ENERGY_MAP_LAYERS — pipelines, waterways, ais, commodityHubs, minerals, sanctions, outages, natural, weather, fires, economic. Intentionally omitted: commodityPorts, climate, tradeRoutes, resilienceScore, dayNight — none of these have render handlers in Map.ts's SVG path, so including them would create toggles that do nothing. Extended the ternary with 'energy' → energyLayers between 'happy' and the 'full' fallback. Note (preexisting, NOT fixed here): the same ternary has no 'commodity' branch either, so commodity.worldmonitor.app also gets the full geopolitical toggle set on the SVG fallback. Out of scope for this PR; flagged for a separate fix. Defence-in-depth: sanitizeLayersForVariant() (now fixed in map-layer-definitions.ts) strips saved-URL layers to the energy subset before the SVG map sees them, so even if a user arrives with ?layers=military in the URL, it's gone by the time initialState reaches MapComponent. The toggle-list fix closes the UI-path leak; the sanitize fix closes the URL-path leak. Typecheck clean. |
||
|
|
4c9888ac79 |
docs(mintlify): panel reference pages (PR 2) (#3213)
* docs(mintlify): add user-facing panel reference pages (PR 2)
Six new end-user pages under docs/panels/ for the shipped panels that
had no user-facing documentation in the published docs, per the plan
docs/plans/2026-04-19-001-feat-docs-user-facing-ia-refresh-plan.md.
All claims are grounded in the live component source + SEED_META +
handler dirs — no invented fields, counts, or refresh windows.
- panels/latest-brief.mdx — daily AI brief panel (ready/composing/
locked states). Hard-gated PRO (`premium: 'locked'`).
- panels/forecast.mdx — AI Forecasts panel (internal id `forecast`,
label "AI Forecasts"). Domain + macro-region filter pills; 10%
probability floor. Free on web, locked on desktop.
- panels/consumer-prices.mdx — 5-tab retail-price surface (Overview
/ Categories / Movers / Spread / Health) with market, basket, and
7/30/90-day controls. Free.
- panels/disease-outbreaks.mdx — WHO / ProMED / national health
ministries outbreak alerts with alert/warning/watch pills. Free.
- panels/radiation-watch.mdx — EPA RadNet + Safecast observations
with anomaly scoring and source-confidence synthesis. Free.
- panels/thermal-escalation.mdx — FIRMS/VIIRS thermal clusters with
persistence and conflict-adjacency flags. Free.
Also:
- docs/docs.json — new Panels nav group (Latest Brief, AI Forecasts,
Consumer Prices, Disease Outbreaks, Radiation Watch, Thermal
Escalation).
- docs/features.mdx — cross-link every panel name in the Cmd+K
inventory to its new page (and link Country Instability + Country
Resilience from the same list).
- docs/methodology/country-resilience-index.mdx — short "In the
dashboard" bridge section naming the three CRI surfaces
(Resilience widget, Country Deep-Dive, map choropleth) so the
methodology page doubles as the user-facing panel reference for
CRI. No separate docs/panels/country-resilience.mdx — keeps the
methodology page as the single source of truth.
* docs(panels): fix Latest Brief polling description
Reviewer catch: the panel does schedule a 60-second re-poll while
in the composing state. `COMPOSING_POLL_MS = 60_000` at
src/components/LatestBriefPanel.ts:78, and `scheduleComposingPoll()`
is called from `renderComposing()` at :366. The poll auto-promotes
the panel to ready without a manual refresh and is cleared when
the panel leaves composing. My earlier 'no polling timer' line was
right for the ready state but wrong as a blanket claim.
* docs(panels): fix variant-availability claims across all 6 panel pages
Reviewer catch on consumer-prices surfaced the same class of error
on 4 other panel pages: I described variant availability with loose
phrasing ('most variants', 'where X context is relevant', 'tech/
finance/happy opt-in') that didn't match the actual per-variant
panel registries in src/config/panels.ts.
Verified matrix against each *_PANELS block directly:
Panel | FULL | TECH | FINANCE | HAPPY | COMMODITY
consumer-prices | opt | - | def | - | def
latest-brief | def | def | def | - | def (all PRO-locked)
disease-outbreaks | def | - | - | - | -
radiation-watch | def | - | - | - | -
thermal-escalation | def | - | - | - | -
forecast | def | - | - | - | - (PRO-locked on desktop)
All 6 pages now name the exact variant blocks in src/config/panels.ts
that register them, so the claim is re-verifiable by grep rather than
drifting with future panel-registry changes.
* docs(panels): fix 5 reviewer findings — no invented controls/sources/keys
All fixes cross-checked against source.
- consumer-prices: no basket selector UI exists. The panel has a
market bar, a range bar, and tab/category affordances; basket is
derived from market selection (essentials-<code>, or DEFAULT_BASKET
for the 'all' aggregate view). Per
src/components/ConsumerPricesPanel.ts:120-123 and :216-229.
- disease-outbreaks: 'Row click opens advisory' was wrong. The only
interactive elements in-row are the source-name <a> link
(sanitised URL, target=_blank); clicking the row itself is a no-op
(the only content-level listener is for [data-filter] pills and
the search input). Per DiseaseOutbreaksPanel.ts:35-49,115-117.
- disease-outbreaks: upstream list was wrong. Actual seeder uses
WHO DON (JSON API), CDC HAN (RSS), Outbreak News Today
(aggregator), and ThinkGlobalHealth disease tracker
(ProMED-sourced, 90d lookback). Noted the in-panel tooltip's
shorter 'WHO, ProMED, health ministries' summary and gave the full
upstream list with the 72h Redis TTL. Per seed-disease-outbreaks
.mjs:31-38.
- radiation-watch: summary bar renders 6 cards, not 7 — Anomalies,
Elevated, Confirmed, Low Confidence, Conflicts, Spikes. The
CPM-derived indicator is a per-row badge (radiation-flag-converted
at :67), not a summary card. Moved the CPM reference to the
per-row badges list. Per RadiationWatchPanel.ts:85-112.
- latest-brief: Redis key shape corrected. The composer writes the
envelope to brief:{userId}:{issueSlot} (where issueSlot comes from
issueSlotInTz, not a plain date) and atomically writes a latest
pointer at brief:latest:{userId} → {issueSlot}. Readers resolve
via the pointer. 7-day TTL on both. Per
seed-digest-notifications.mjs:1103-1115 and
api/latest-brief.ts:80-89.
* docs(panels): Tier 1 — PRO/LLM panel reference pages (9)
Adds user-facing panel pages for the 9 PRO/LLM-backed surfaces flagged
in the extended audit. All claims grounded in component source +
src/config/panels.ts entries (with line cites).
- panels/chat-analyst.mdx — WM Analyst (conversational AI, 5 quick
actions, 4 domain scopes, POSTs /api/chat-analyst via premiumFetch).
- panels/market-implications.mdx — AI Market Implications trade signals
(LONG/SHORT/HEDGE × HIGH/MEDIUM/LOW, transmission paths, 120min
maxStaleMin, degrade-to-warn). Carries the repo's disclaimer verbatim.
- panels/deduction.mdx — Deduct Situation (opt-in PRO; 5s cooldown;
composes buildNewsContext + active framework).
- panels/daily-market-brief.mdx — Daily Market Brief (stanced items,
framework selector, live vs cached source badge).
- panels/regional-intelligence.mdx — Regional Intelligence Board
(7 BOARD_REGIONS, 6 structured blocks + narrative sections,
request-sequence arbitrator, opt-in PRO).
- panels/strategic-posture.mdx — AI Strategic Posture (cached posture
+ live military vessels → recalcPostureWithVessels; free on web,
enhanced on desktop).
- panels/stock-analysis.mdx — Premium Stock Analysis (per-ticker
deep dive: signal, targets, consensus, upgrades, insiders, sparkline).
- panels/stock-backtest.mdx — Premium Backtesting (longitudinal view;
live vs cached data badge).
- panels/wsb-ticker-scanner.mdx — WSB Ticker Scanner (retail sentiment
+ velocity score with 4-tier color bucketing).
All 9 are PRO (8 via apiKeyPanels allowlist at src/config/panels.ts:973,
strategic-posture is free-on-web/enhanced-on-desktop). Variant matrices
name the exact *_PANELS block registering each panel.
* docs(panels): Tier 2 — flagship free data panels (7)
Adds reference pages for 7 flagship free panels. Every claim grounded
in the panel component + src/config/panels.ts per-variant registration.
- panels/airline-intel.mdx — 6-tab aviation surface (ops/flights/
airlines/tracking/news/prices), 8 aviation RPCs, user watchlist.
- panels/tech-readiness.mdx — ranked country tech-readiness index with
6-hour in-panel refresh interval.
- panels/trade-policy.mdx — 6-tab trade-policy surface (restrictions/
tariffs/flows/barriers/revenue/comtrade).
- panels/supply-chain.mdx — composite stress + carriers + minerals +
Scenario Engine trigger surface (free panel, PRO scenario activation).
- panels/sanctions-pressure.mdx — OFAC SDN + Consolidated list
pressure rollup with new/vessels/aircraft summary cards and top-8
country rows.
- panels/hormuz-tracker.mdx — Hormuz chokepoint drill-down; status
indicator + per-series bar charts; references Scenario Engine's
hormuz-tanker-blockade template.
- panels/energy-crisis.mdx — IEA 2026 Energy Crisis Policy Response
Tracker; category/sector/status filters.
All 7 are free. Variant matrices name exact *_PANELS blocks
registering each panel.
* docs(panels): Tier 3 — compact panels (5)
Adds reference pages for 5 compact user-facing panels.
- panels/world-clock.mdx — 22 global market-centre clocks with
exchange labels + open/closed indicators (client-side only).
- panels/monitors.mdx — personal keyword alerts, localStorage-persisted;
links to Features → Custom Monitors for longer explanation.
- panels/oref-sirens.mdx — OREF civil-defence siren feed; active +
24h wave history; free on web, PRO-locked on desktop (_desktop &&
premium: 'locked' pattern).
- panels/telegram-intel.mdx — topic-tabbed Telegram channel mirror
via relay; free on web, PRO-locked on desktop.
- panels/fsi.mdx — US KCFSI + EU FSI stress composites with
four-level colour buckets (Low/Moderate/Elevated/High).
All 5 grounded in component source + variant registrations.
oref-sirens and telegram-intel correctly describe the _desktop &&
locking pattern rather than the misleading 'PRO' shorthand used
earlier for other desktop-locked panels.
* docs(panels): Tier 4 + 5 catalogue pages, nav re-grouping, features cross-links
Closes out the comprehensive panel-reference expansion. Two catalogue
pages cover the remaining ~60 panels collectively so they're all
searchable and findable without dedicated pages per feed/tile.
- panels/news-feeds.mdx — catalogue covering all content-stream panels:
regional news (africa/asia/europe/latam/us/middleeast/politics),
topical news (climate/crypto/economic/markets/mining/commodity/
commodities), tech/startup streams (startups/unicorns/accelerators/
fintech/ipo/layoffs/producthunt/regionalStartups/thinktanks/vcblogs/
defense-patents/ai-regulation/tech-hubs/ai/cloud/hardware/dev/
security/github), finance streams (bonds/centralbanks/derivatives/
forex/institutional/policy/fin-regulation/commodity-regulation/
analysis), happy variant streams (species/breakthroughs/progress/
spotlight/giving/digest/events/funding/counters/gov/renewable).
- panels/indicators-and-signals.mdx — catalogue covering compact
market-indicator tiles, correlation panels, and misc signal surfaces.
Grouped by function: sentiment, macro, calendars, market-structure,
commodity, crypto, regional economy, correlation panels, misc signals.
docs/docs.json — split the Panels group into three for navigability:
- Panels — AI & PRO (11 pages)
- Panels — Data & Tracking (16 pages)
- Panels — Catalogues (2 pages)
docs/features.mdx — Cmd+K inventory rewritten as per-family sub-lists
with links to every panel page (or catalogue page for the ones
that live in a catalogue). Replaces the prior run-on paragraph.
Every catalogue panel is also registered in at least one *_PANELS
block in src/config/panels.ts — the catalogue pages note this and
point readers to the config file for variant-availability details.
* docs(panels): fix airline-intel + world-clock source-of-truth errors
- airline-intel: refresh behavior section was wrong on two counts.
(1) The panel DOES have a polling timer: a 5-minute setInterval
in the constructor calling refresh() (which reloads ops + active
tab). (2) The 'prices' tab does NOT re-fetch on tab switch —
it's explicitly excluded from both tab-switch and auto-refresh
paths, loading only on explicit search-button click. Three
distinct refresh paths now documented with source line hints.
Per src/components/AirlineIntelPanel.ts ~:173 (setInterval),
:287 (prices tab-switch guard), :291 (refresh() prices skip).
- world-clock: the WORLD_CITIES list has 30 entries, not '~22'.
Replaced the approximate count with the exact number and a
:14-43 line-range cite so it's re-verifiable.
|
||
|
|
d1a4cf7780 |
docs(mintlify): add Route Explorer + Scenario Engine workflow pages (#3211)
* docs(mintlify): add Route Explorer + Scenario Engine workflow pages Checkpoint for review on the IA refresh (per plan docs/plans/2026-04-19-001-feat-docs-user-facing-ia-refresh-plan.md). - docs/docs.json: link Country Resilience Index methodology under Intelligence & Analysis so the flagship 222-country feature is reachable from the main nav (previously orphaned). Add a new Workflows group containing route-explorer and scenario-engine. - docs/route-explorer.mdx: standalone workflow page. Who it is for, Cmd+K entry, four tabs (Current / Alternatives / Land / Impact), inputs, keyboard bindings, map-state integration, PRO gating with free-tier blur + public-route highlight, data sources. - docs/scenario-engine.mdx: standalone workflow page. Template categories (conflict / weather / sanctions / tariff_shock / infrastructure / pandemic), how a scenario activates on the map, PRO gating, pointers to the async job API. Deferred to follow-up commits in the same PR: - documentation.mdx landing rewrite - features.mdx refresh - maritime-intelligence.mdx link-out to Route Explorer - Panels nav group (waits for PR 2 content) All content grounded in live source files cited inline. * docs(mintlify): fix Route Explorer + Scenario Engine review findings Reviewer caught 4 cases where I described behavior I hadn't read carefully. All fixes cross-checked against source. - route-explorer (free-tier): the workflow does NOT blur a numeric payload behind a public demo route. On free tier, fetchLane() short-circuits to renderFreeGate() which blurs the left rail, replaces the tab area with an Upgrade-to-PRO card, and applies a generic public-route highlight on the map. No lane data is rendered in any tab. See src/components/RouteExplorer/ RouteExplorer.ts:212 + :342. - route-explorer (keyboard): Tab / Shift+Tab moves focus between the panel and the map. Direct field jumps are F (From), T (To), P (Product/HS2), not Tab-cycling. Also added the full KeyboardHelp binding list (S swap, ↑/↓ list nav, Enter commit, Cmd+, copy URL, Esc close, ? help, 1-4 tabs). See src/components/RouteExplorer/ KeyboardHelp.ts:9 and RouteExplorer.ts:623. - scenario-engine: the SCENARIO_TEMPLATES array only ships templates of 4 types today (conflict, weather, sanctions, tariff_shock). The ScenarioType union includes infrastructure and pandemic but no templates of those types ship. Dropped them from the shipped table and noted the type union leaves room for future additions. - scenario-engine + api-scenarios: the worker writes status: 'done' (not 'completed') on success, 'failed' on error; pending is synthesised by the status endpoint when no worker record exists. Fixed both the new workflow page and the merged api-scenarios.mdx completed-response example + polling language. See scripts/scenario-worker.mjs:421 and src/components/SupplyChainPanel.ts:870. * docs(mintlify): fix third-round review findings (real IDs + 4-state lifecycle) - api-scenarios (template example): replaced invented hormuz-closure-30d / ["hormuz"] with the actually-shipped hormuz-tanker-blockade / ["hormuz_strait"] from scenario- templates.ts:80. Listed the other 5 shipped template IDs so scripted users aren't dependent on a single example. - api-scenarios (status lifecycle): worker writes FOUR states, not three. Added the intermediate "processing" state with startedAt, written by the worker at job pickup (scenario- worker.mjs:411). Lifecycle now: pending → processing → done|failed. Both pending and processing are non-terminal. - scenario-engine (scripted use blurb): mirror the 4-state language and link into the lifecycle table. - scenario-engine (UI dismiss): replaced "Click Deactivate" with the actual × dismiss control on the scenario banner (aria-label: "Dismiss scenario") per src/components/SupplyChainPanel.ts:790. Also described the banner contents (name, chokepoints, countries, tagline). - api-shipping-v2: while fixing chokepoint IDs, also corrected "hormuz" → "hormuz_strait" and "bab-el-mandeb" → "bab_el_mandeb" across all four occurrences in the shipping v2 page (from PR #3209). Real IDs come from server/_shared/chokepoint- registry.ts (snake_case, not kebab-case, not bare "hormuz"). * docs(mintlify): fix fourth-round findings (banner DOM, webhook TTL refresh) - scenario-engine: accurate description of the rendered scenario banner. Always-present elements are the ⚠ icon, scenario name, top-5 impacted countries with impact %, and dismiss ×. Params chip (e.g. '14d · +110% cost') and 'Simulating …' tagline are conditional on the worker result carrying template parameters (durationDays, disruptionPct, costShockMultiplier). The banner never lists affected chokepoints by name — the map and the chokepoint cards surface those. Per renderScenarioBanner at src/components/SupplyChainPanel.ts:750. - api-shipping-v2 (webhook TTL): register extends both the record and the owner-index set's 30-day TTL via atomic pipeline (SET + SADD + EXPIRE). rotate-secret and reactivate only extend the record's TTL — neither touches the owner-index set, so the owner index can expire independently if a caller only rotates/reactivates within a 30-day window. Re-register to keep both alive. Per api/v2/shipping/webhooks.ts:230 (register pipeline) and :325 (rotate setCachedJson on record only). * docs(mintlify): fix PRO auth contract (trusted origin ≠ PRO) - api-scenarios: 'X-WorldMonitor-Key (or trusted browser origin) + PRO' was wrong — isCallerPremium() explicitly skips trusted-origin short-circuits (keyCheck.required === false) and only counts (a) an env-valid or user-owned wm_-prefixed API key with apiAccess entitlement, or (b) a Clerk bearer with role=pro or Dodo tier ≥ 1. Browser calls work because premiumFetch() injects one of those credentials per request, not because Origin alone authenticates. Per server/_shared/premium-check.ts:34 and src/services/premium-fetch.ts:66. - usage-auth: strengthened the 'Entitlement / tier gating' section to state outright that authentication and PRO entitlement are orthogonal, and that trusted Origin is NOT accepted as PRO even though it is accepted for public endpoints. Listed the two real credential forms that pass the gate. * docs(mintlify): fix stale line cite (MapContainer.activateScenario at :1010) Greptile review P2: prose cited MapContainer.ts:1004 but activateScenario is declared at :1010. Line 1004 landed inside the JSDoc block. * docs(mintlify): finish PR 1 — landing rewrite, features refresh, maritime link-out Completes the PR 1 items from docs/plans/2026-04-19-001-feat-docs-user- facing-ia-refresh-plan.md that were deferred after the checkpoint on Route Explorer + Scenario Engine + CRI nav. No new pages — only edits to existing pages to point at and cohere with the new workflow pages. - documentation.mdx: landing rewrite. Dropped brittle counts (344 news sources, 49 layers, 24 CII countries, 31+ sources, 24 typed services) in favor of durable product framing. Surfaced the shipped differentiators that were invisible on the landing previously: Country Resilience Index (222 countries, linked to its methodology page), AI daily brief, Route Explorer, Scenario Engine, MCP server. Kept CII and CRI as two distinct country-risk surfaces — do not conflate. - features.mdx: replaced the 'all 55 panels' Cmd+K claim and the stale inventory list with family-grouped descriptions that include the panels this audit surfaced as missing (disease- outbreaks, radiation-watch, thermal-escalation, consumer-prices, latest-brief, forecast, country-resilience). Added a Workflows section linking to Route Explorer and Scenario Engine, and a Country-level risk section linking CII + CRI. Untouched sections (map, marker clustering, data layers, export, monitors, activity tracking) left as-is. - maritime-intelligence.mdx: collapsed the embedded Route Explorer subsection to a one-paragraph pointer at /route-explorer so the standalone page is the canonical home. Panels nav group remains intentionally unadded; it waits on PR 2 content to avoid rendering an empty group in Mintlify. |
||
|
|
e4c95ad9be |
docs(mintlify): cover MCP, OAuth, non-RPC endpoints, and usage (#3209)
* docs(mintlify): cover MCP, OAuth, non-RPC endpoints, and usage Audit against api/ + proto/ revealed 9 OpenAPI specs missing from nav, the scenario/v1 service undocumented, and MCP (32 tools + OAuth 2.1 flow) with no user-facing docs. The stale Docs_To_Review/API_REFERENCE.md still pointed at pre-migration endpoints that no longer exist. - Wire 9 orphaned specs into docs.json: ConsumerPrices, Forecast, Health, Imagery, Radiation, Resilience, Sanctions, Thermal, Webcam - Hand-write ScenarioService.openapi.yaml (3 RPCs) until it's proto-backed (tracked in issue #3207) - New MCP page with tool catalog + client setup (Claude Desktop/web, Cursor) - New MDX for OAuth, Platform, Brief, Commerce, Notifications, Shipping v2, Proxies - New Usage group: quickstart, auth matrix, rate limits, errors - Remove docs/Docs_To_Review/API_REFERENCE.md and EXTERNAL_APIS.md (referenced dead endpoints); add README flagging dir as archival * docs(mintlify): move scenario docs out of generated docs/api/ tree The pre-push hook enforces that docs/api/ is proto-generated only. Replace the hand-written ScenarioService.openapi.yaml with a plain MDX page (docs/api-scenarios.mdx) until the proto migration lands (tracked in issue #3207). * docs(mintlify): fix factual errors flagged in PR review Reviewer caught 5 endpoints where I speculated on shape/method/limits instead of reading the code. All fixes cross-checked against the source: - api-shipping-v2: route-intelligence is GET with query params (fromIso2, toIso2, cargoType, hs2), not POST with a JSON body. Response shape is {primaryRouteId, chokepointExposures[], bypassOptions[], warRiskTier, disruptionScore, ...}. - api-commerce: /api/product-catalog returns {tiers, fetchedAt, cachedUntil, priceSource} with tier groups free|pro|api_starter| enterprise, not the invented {currency, plans}. Document the DELETE purge path too. - api-notifications: Slack/Discord /oauth/start are POST + Clerk JWT + PRO (returning {oauthUrl}), not GET redirects. Callbacks remain GET. - api-platform: /api/version returns the latest GitHub Release ({version, tag, url, prerelease}), not deployed commit/build metadata. - api-oauth + mcp: /api/oauth/register limit is 5/60s/IP (match code), not 10/hour. Also caught while double-checking: /api/register-interest and /api/contact are 5/60min and 3/60min respectively (1-hour window, not 1-minute). Both require Turnstile. Removed the fabricated limits for share-url, notification-channels, create-checkout (they fall back to the default per-IP limit). * docs(mintlify): second-round fixes — verify every claim against source Reviewer caught 7 more cases where I described API behavior I hadn't read. Each fix below cross-checked against the handler. - api-commerce (product-catalog): tiers are flat objects with monthlyPrice/annualPrice/monthlyProductId/annualProductId on paid tiers, price+period for free, price:null for enterprise. There is no nested plans[] array. - api-commerce (referral/me): returns {code, shareUrl}, not counts. Code is a deterministic 8-char HMAC of the Clerk userId; binding into Convex is fire-and-forget via ctx.waitUntil. - api-notifications (notification-channels): actual action set is create-pairing-token, set-channel, set-web-push, delete-channel, set-alert-rules, set-quiet-hours, set-digest-settings. Replaced the made-up list. - api-shipping-v2 (webhooks): alertThreshold is numeric 0-100 (default 50), not a severity string. Subscriber IDs are wh_+24hex; secret is raw 64-char hex (no whsec_ prefix). POST registration returns 201. Added the management routes: GET /{id}, POST /{id}/rotate-secret, POST /{id}/reactivate. - api-platform (cache-purge): auth is Authorization: Bearer RELAY_SHARED_SECRET, not an admin-key header. Body takes keys[] and/or patterns[] (not {key} or {tag}), with explicit per-request caps and prefix-blocklist behavior. - api-platform (download): platform+variant query params, not file=<id>. Response is a 302 to a GitHub release asset; documented the full platform/variant tables. - mcp: server also accepts direct X-WorldMonitor-Key in addition to OAuth bearer. Fixed the curl example which was incorrectly sending a wm_live_ API key as a bearer token. - api-notifications (youtube/live): handler reads channel or videoId, not channelId. - usage-auth: corrected the auth-matrix row for /api/mcp to reflect that OAuth is one of two accepted modes. * docs(mintlify): fix Greptile review findings - mcp.mdx: 'Five' slow tools → 'Six' (list contains 6 tools) - api-scenarios.mdx: replace invalid JSON numeric separator (8_400_000_000) with plain integer (8400000000) Greptile's third finding — /api/oauth/register rate-limit contradiction across api-oauth.mdx / mcp.mdx / usage-rate-limits.mdx — was already resolved in commit |
||
|
|
a969a9e3a3 |
feat(auth): integrate clerk.dev (#1812)
* feat(auth): integrate better-auth with @better-auth/infra dash plugin Wire up better-auth server config with the dash() plugin from @better-auth/infra, and the matching sentinelClient() on the client side. Adds BETTER_AUTH_API_KEY to .env.example. * feat(auth): swap @better-auth/infra for @convex-dev/better-auth [10-01 task 1] Install @convex-dev/better-auth@0.11.2, remove @better-auth/infra, delete old server/auth.ts skeleton, rewrite auth-client.ts to use crossDomainClient + convexClient plugins. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat(auth): create Convex auth component files [10-01 task 2] Add convex.config.ts (register betterAuth component), auth.config.ts (JWT/JWKS provider), auth.ts (better-auth server with Convex adapter, crossDomain + convex plugins), http.ts (mount auth routes with CORS). Uses better-auth/minimal for lighter bundle. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat(auth): add admin, organization, and dash plugins [10-01] Re-install @better-auth/infra for dash() plugin to enable dash.better-auth.com admin dashboard. Add admin() and organization() plugins from better-auth/plugins for user and org management. Update both server (convex/auth.ts) and client (auth-client.ts). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(auth): drop @better-auth/infra (Node.js deps incompatible with Convex V8) Keep admin() and organization() from better-auth/plugins (V8-safe). @better-auth/infra's dash() transitively imports SAML/SSO with node:crypto, fs, zlib — can't run in Convex's serverless runtime. Dashboard features available via admin plugin endpoints instead. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat(11-01): create auth-state.ts with OTT handler and session subscription - Add initAuthState() for OAuth one-time token verification on page load - Add subscribeAuthState() reactive wrapper around useSession nanostore atom - Add getAuthState() synchronous snapshot getter - Export AuthUser and AuthSession types for UI consumption Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat(11-01): add Google OAuth provider and wire initAuthState into App.ts - Add socialProviders.google with GOOGLE_CLIENT_ID/SECRET to convex/auth.ts - Add all variant subdomains to trustedOrigins for cross-subdomain CORS - Call initAuthState() in App.init() before panelLayout.init() - Add authModal field to AppContext interface (prepares for Plan 02) - Add authModal: null to App constructor state initialization Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat(11-02): create AuthModal with Sign In/Sign Up tabs and Google OAuth - Sign In tab: email/password form calling authClient.signIn.email() - Sign Up tab: name/email/password form calling authClient.signUp.email() - Google OAuth button calling authClient.signIn.social({ provider: 'google', callbackURL: '/' }) - Auto-close on successful auth via subscribeAuthState() subscription - Escape key, overlay click, and X button close the modal - Loading states, error display, and client-side validation Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat(11-02): add AuthHeaderWidget, mount in header, add auth CSS - AuthHeaderWidget: reactive header widget showing Sign In button (anonymous) or avatar + dropdown (authenticated) - User dropdown: name, email, Free tier badge, Sign Out button calling authClient.signOut() - setupAuthWidget() in EventHandlerManager creates modal + widget, mounts at authWidgetMount span - authWidgetMount added to panel-layout.ts header-right, positioned before download wrapper - setupAuthWidget() called from App.ts after setupUnifiedSettings() - Full auth CSS: modal styles, tabs, forms, Google button, header widget, avatar, dropdown Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(11-02): add localhost:3000 to trustedOrigins for local dev CORS Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(auth): remove admin/organization plugins that break Convex adapter validator The admin() plugin adds banned/role fields to user creation data, but the @convex-dev/better-auth adapter validator doesn't include them. These plugins are Phase 12 work — will re-add with additionalFields config when needed. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat(12-01): add Resend email transport, verification + reset callbacks, role field - Install resend SDK for transactional email - Add emailVerification with sendOnSignUp:true and fire-and-forget Resend callbacks - Add sendResetPassword callback with 1-hour token expiry - Add user.additionalFields.role (free/pro, input:false, defaultValue:free) - Create userRoles fallback table in schema with by_userId index - Create getUserRole query and setUserRole mutation in convex/userRoles.ts - Lazy-init Resend client to avoid Convex module analysis error Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat(12-01): enhance auth-state with emailVerified and role fields - Add emailVerified (boolean) and role ('free' | 'pro') to AuthUser interface - Fetch role from Convex userRoles table via HTTP query after session hydration - Cache role per userId to avoid redundant fetches - Re-notify subscribers asynchronously when role is fetched for a new user - Map emailVerified from core better-auth user field (default false) - Derive Convex cloud URL from VITE_CONVEX_SITE_URL env var Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * chore(12-01): add Convex generated files from deployment - Track convex/_generated/ files produced by npx convex dev --once Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat(12-03): create panel-gating service with auth-aware showGatedCta - Add PanelGateReason enum (NONE/ANONYMOUS/UNVERIFIED/FREE_TIER) - Add getPanelGateReason() computing gating from AuthSession + premium flag - Add Panel.showGatedCta() rendering auth-aware CTA overlays - Add Panel.unlockPanel() to reverse locked state - Extract lockSvg to module-level const shared by showLocked/showGatedCta - Add i18n keys: signInToUnlock, signIn, verifyEmailToUnlock, resendVerification, upgradeDesc, upgradeToPro Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat(12-02): add forgot password flow, password reset form, and token detection - Widen authModal interface in app-context.ts to support reset-password mode and setResetToken - AuthModal refactored with 4 views: signin, signup, forgot-password, reset-password - Forgot password view sends reset email via authClient.requestPasswordReset - Reset password form validates matching passwords and calls authClient.resetPassword - auth-state.ts detects ?token= param from email links, stores as pendingResetToken - App.ts routes pending reset token to auth modal after UI initialization - CSS for forgot-link, back-link, and success message elements Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat(12-02): add email verification banner to AuthHeaderWidget and tier badge - Show non-blocking verification banner below header for unverified users - Banner has "Resend" button calling authClient.sendVerificationEmail - Banner is dismissible (stored in sessionStorage, reappears next session) - Tier badge dynamically shows Free/Pro based on user.role - Pro badge has gradient styling distinct from Free badge - Dropdown shows unverified status indicator with yellow dot - Banner uses fixed positioning, does not push content down - CSS for banner, pro badge, and verification status indicators Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat(12-03): wire reactive auth-based gating into panel-layout - Add WEB_PREMIUM_PANELS Set (stock-analysis, stock-backtest, daily-market-brief) - Subscribe to auth state changes in PanelLayoutManager.init() - Add updatePanelGating() iterating panels with getPanelGateReason() - Add getGateAction() returning CTA callbacks per gate reason - Remove inline showLocked() calls for web premium panels - Preserve desktop _lockPanels for forecast, oref-sirens, telegram-intel - Clean up auth subscription in destroy() Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat(13-01): create auth-token utility and inject Bearer header in web fetch redirect - Add src/services/auth-token.ts with getSessionBearerToken() that reads session token from localStorage - Add WEB_PREMIUM_API_PATHS Set for the 4 premium market API paths - Inject Authorization: Bearer header in installWebApiRedirect() for premium paths when session exists - Desktop installRuntimeFetchPatch() left unchanged (API key only) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat(13-01): create server-side session validation module - Add server/auth-session.ts with validateBearerToken() for Vercel edge gateway - Validates tokens via Convex /api/auth/get-session with Better-Auth-Cookie header - Falls back to userRoles:getUserRole Convex query for role resolution - In-memory cache with 60s TTL and 100-entry cap - Network errors not cached to allow retry on next request Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat(13-02): add bearer token fallback auth for premium API endpoints - Dynamic import of auth-session.ts when premium endpoint + API key fails - Valid pro session tokens fall through to route handler - Non-pro authenticated users get 403 'Pro subscription required' - Invalid/expired tokens get 401 'Invalid or expired session' - Non-premium endpoints and static API key flow unchanged Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(auth): sign-in button invisible in dark theme — white on white --accent is #fff in dark theme, so background: var(--accent) + color: #fff was invisible. Changed to transparent background with var(--text) color. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(auth): add premium panel keys to full and finance variant configs stock-analysis, stock-backtest, and daily-market-brief were defined in the shared panels.ts but missing from variant DEFAULT_PANELS, causing shouldCreatePanel() to return false and panel gating CTAs to never render. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * test(auth): add Playwright smoke tests for auth UI (phases 12-13) 6 tests covering: Sign In button visibility, auth modal opening, modal views (Sign In/Sign Up/Forgot Password), premium panel gating for anonymous users, and auth token absence when logged out. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(auth): remove role additionalField that breaks Convex component validator The betterAuth Convex component has a strict input validator for the user model that doesn't include custom fields. The role additionalField caused ArgumentValidationError on sign-up. Roles are already stored in the separate userRoles table — no data loss. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(auth): use Authorization Bearer header for Convex session validation Better-Auth-Cookie header returned null — the crossDomain plugin's get-session endpoint expects Authorization: Bearer format instead. Confirmed via curl against live Convex deployment. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(auth): use verified worldmonitor.app domain for auth emails Was using noreply@resend.dev (testing domain) which can't send to external recipients. Switched to noreply@worldmonitor.app matching existing waitlist/contact emails. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(auth): await Resend email sends — Convex kills dangling promises void (fire-and-forget) causes Convex to terminate the fetch before Resend receives it. Await ensures emails actually get sent. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * chore: update Convex generated auth files after config changes Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(auth): guard against undefined VITE_CONVEX_SITE_URL in auth-state The Convex cloud URL derivation crashed the entire app when VITE_CONVEX_SITE_URL wasn't set in the build environment (Vercel preview). Now gracefully defaults to empty string and skips role fetching when the URL is unavailable. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat(auth): add dash + organization plugins, remove Google OAuth, fix dark mode button - Add @better-auth/infra dash plugin for hosted admin dashboard - Add organization plugin for org management in dashboard - Add dash.better-auth.com to trustedOrigins - Remove Google OAuth (socialProviders, button, divider, CSS) - Fix auth submit button invisible in dark mode (var(--accent) → #3b82f6) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(auth): replace dash plugin with admin — @better-auth/infra incompatible with Convex V8 @better-auth/infra imports SSO/SAML libraries requiring Node.js built-ins (crypto, fs, stream) which Convex's V8 runtime doesn't support. Replaced with admin plugin from better-auth/plugins which provides user management endpoints (set-role, list-users, ban, etc.) natively. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * chore: remove stale Convex generated files after plugin update Convex dev regenerated _generated/ — the per-module JS files (auth.js, http.js, schema.js, etc.) are no longer emitted. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * chore(auth): remove organization plugin — will add in subsequent PR Organization support (team accounts, invitations, member management) is not wired into any frontend flow yet. Removing to keep the auth PR focused on email/password + admin endpoints. Will add back when building the org/team feature. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * docs: add authentication & panel gating guide Documents the auth stack, panel gating configuration, server-side session enforcement, environment variables, and user roles. Includes step-by-step guide for adding new premium panels. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(test): stub panel-gating in RuntimeConfigPanel test harness Panel.ts now imports @/services/panel-gating, which wasn't stubbed — causing the real runtime.ts (with window.location) to be bundled, breaking Node.js tests with "ReferenceError: location is not defined". Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(auth): allow Vercel preview origins in Convex trustedOrigins * fix(auth): broaden Convex trustedOrigins to cover *.worldmonitor.app previews * fix(auth): use hostonly wildcard pattern for *.worldmonitor.app in trustedOrigins * fix(auth): add Convex site origins to trustedOrigins * fix(ci): add convex/ to vercel-ignore watched paths * fix(auth): remove admin() plugin — adds banned/role fields rejected by Convex validator * fix(auth): remove admin() plugin — injects banned/role fields rejected by Convex betterAuth validator * feat(auth): replace email/password with email OTP passwordless flow - Replace emailAndPassword + emailVerification with emailOTP plugin - Rewrite AuthModal: email entry -> OTP code verification (no passwords) - Remove admin() plugin (caused Convex schema validation errors) - Remove email verification banner and UNVERIFIED gate reason (OTP inherently verifies email) - Remove password reset flow (forgot/reset password views, token handling) - Clean up unused CSS (tabs, verification banner, success messages) - Update docs to reflect new passwordless auth stack Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(quick-2): harden Convex userRoles and add role cache TTL - P0: Convert setUserRole from mutation to internalMutation (not callable from client) - P2: Add 5-minute TTL to role cache in auth-state.ts - P2: Add localStorage shape warning on auth-token.ts - P3: Document getUserRole public query trade-off - P3: Fix misleading cache comment in auth-session.ts Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(quick-2): auth widget teardown, E2E test rewrite, gateway comment - P2: Store authHeaderWidget on AppContext, destroy in EventHandlerManager.destroy() - P2: Also destroy authModal in destroy() to prevent leaked subscriptions - P1: Rewrite E2E tests for 2-view OTP modal (email input + submit button) - P1: Remove stale "Sign Up" and "Forgot Password" test assertions - P2: Replace flaky waitForTimeout(5000) with Playwright auto-retry assertion - P3: Add clarifying comment on premium bearer-token fallback in gateway Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat(header): restructure header/footer, add profile editing, pro-gate playback/export - Remove version, @eliehabib, GitHub link, and download button from header - Move version + @eliehabib credit to footer brand line; download link to footer nav - Move auth widget (profile avatar) to far right of header (after settings gear) - Add default generic SVG avatar for users with no image and no name - Add profile editing in auth dropdown: display name + avatar URL with Save/Cancel - Add Settings shortcut in auth dropdown (opens UnifiedSettings) - Gate Historical Playback and Export controls behind pro role (hidden for free users) - Reactive pro-gate: subscribes to auth state changes, stores unsub in proGateUnsubscribers[] - Clean up proGateUnsubscribers on EventHandlerManager.destroy() to prevent leaks - Fix: render Settings button unconditionally (hidden via style), stable DOM structure - Fix: typed updateUser call with runtime existence check instead of (any) cast - Make initFooterDownload() private to match class conventions * feat(analytics): add Umami auth integration and event tracking - Wire analytics.ts facade to Umami (port from main #1914): search, country, map layers, panels, LLM, theme, language, variant switch, webcam, download, findings, deeplinks - Add Window.umami shim to vite-env.d.ts - Add initAuthAnalytics() that subscribes to auth state and calls identifyUser(id, role) / clearIdentity() on sign-in/sign-out - Add trackSignIn, trackSignUp, trackSignOut, trackGateHit exports - Call initAuthAnalytics() from App.ts after initAuthState() - Track sign-in/sign-up (via isNewUser flag) in AuthModal OTP verify - Track sign-out in AuthHeaderWidget before authClient.signOut() - Track gate-hit for export, playback (event-handlers) and pro-banner * feat(auth): professional avatar widget with colored initials and clean profile edit - Replace white-circle avatar with deterministic colored initials (Gmail/Linear style) - Avatar color derived from email hash across 8-color palette - Dropdown redesigned: row layout with large avatar + name/email/tier info - Profile edit form: name-only (removed avatar URL field) - Remove Settings button from dropdown (gear icon in header is sufficient) - Discord community widget: single CTA link, no redundant text label - Add all missing CSS for dropdown interior, profile edit form, menu items * fix(auth): lock down billing tier visibility and fix TOCTOU race P1: getUserRole converted to internalQuery — billing tier no longer accessible via any public Convex client API. Exposed only through the new authenticated /api/user-role HTTP action which validates the session Bearer token before returning the role. P1: subscribeAuthState generation counter + AbortController prevents rapid sign-in/sign-out from delivering stale role for wrong user. P2: typed RawSessionUser/RawSessionValue interfaces replace any casts at the better-auth nanostore boundary. fetchUserRole drops userId param — server derives identity from Bearer token only. P2: isNewUser heuristic removed from OTP verify — better-auth emailOTP has no reliable isNewUser signal. All verifications tracked as trackSignIn. OTP resend gets 30s client-side cooldown. P2: auth-token.ts version pin comment added (better-auth@1.5.5 + @convex-dev/better-auth@0.11.2). Gateway inner PREMIUM_RPC_PATHS comment clarified to explain why it is not redundant. Adds tests/auth-session.test.mts: 11 tests covering role fallback endpoint selection, fail-closed behavior, and CORS origin matching. * feat(quick-4): replace better-auth with Clerk JS -- packages, Convex config, browser auth layer - Remove better-auth, @convex-dev/better-auth, @better-auth/infra, resend from dependencies - Add @clerk/clerk-js and jose to dependencies - Rewrite convex/auth.config.ts for Clerk issuer domain - Simplify convex/convex.config.ts (remove betterAuth component) - Delete convex/auth.ts, convex/http.ts, convex/userRoles.ts - Remove userRoles table from convex/schema.ts - Create src/services/clerk.ts with Clerk JS init, sign-in, sign-out, token, user metadata, UserButton - Rewrite src/services/auth-state.ts backed by Clerk (same AuthUser/AuthSession interface) - Delete src/services/auth-client.ts (better-auth client) - Delete src/services/auth-token.ts (localStorage token scraping) - Update .env.example with Clerk env vars, remove BETTER_AUTH_API_KEY Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat(quick-4): UI components, runtime fetch, server-side JWT, CSP, and tests - Delete AuthModal.ts, create AuthLauncher.ts (thin Clerk.openSignIn wrapper) - Rewrite AuthHeaderWidget.ts to use Clerk UserButton + openSignIn - Update event-handlers.ts to use AuthLauncher instead of AuthModal - Rewrite runtime.ts enrichInitForPremium to use async getClerkToken() - Rewrite server/auth-session.ts for jose-based JWT verification with cached JWKS - Update vercel.json CSP: add *.clerk.accounts.dev to script-src and frame-src - Add Clerk CSP tests to deploy-config.test.mjs - Rewrite e2e/auth-ui.spec.ts for Clerk UI - Rewrite auth-session.test.mts for jose-based validation - Use dynamic import for @clerk/clerk-js to avoid Node.js test breakage Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(auth): allow Clerk Pro users to load premium data on web The data-loader gated premium panel loading (stock-analysis, stock-backtest, daily-market-brief) on WORLDMONITOR_API_KEY only, which is desktop-only. Web users with Clerk Pro auth were seeing unlocked panels stuck on "Loading..." because the requests were never made. Added hasPremiumAccess() helper that checks for EITHER desktop API key OR Clerk Pro role, matching the migration plan Phase 7 requirements. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(auth): address PR #1812 review — all 4 merge blockers + 3 gaps Blockers: 1. Remove stale Convex artifacts (http.js, userRoles.js, betterAuth component) from convex/_generated/api.d.ts 2. isProUser() now checks getAuthState().user?.role === 'pro' alongside legacy localStorage keys 3. Finance premium refresh scheduling now fires for Clerk Pro web users (not just API key holders) 4. JWT verification now validates audience: 'convex' to reject tokens scoped to other Clerk templates Gaps: 5. auth-session tests: 10 new cases (valid pro/free, expired, wrong key/audience/issuer, missing sub/plan, JWKS reuse) using self-signed keys + local JWKS server 6. premium-stock-gateway tests: 4 new bearer token cases (pro→200, free→403, invalid→401, public unaffected) 7. docs/authentication.mdx rewritten for Clerk (removed all better-auth references, updated stack/files/env vars/roles sections) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: address P1 reactive Pro UI + P2 daily-market-brief + P3 stale env vars P1 — In-session Pro UI changes no longer require a full reload: - setupExportPanel: removed early isProUser() return, always creates and relies on reactive subscribeAuthState show/hide - setupPlaybackControl: same pattern — always creates, reactive gate - Custom widget panels: always loaded regardless of Pro status - Pro add-panel and MCP add-panel blocks: always rendered, shown/hidden reactively via subscribeAuthState callback - Flight search wiring: always wired, checks Pro status inside callback so mid-session sign-ins work immediately P2 — daily-market-brief added to hasPremiumAccess() block in loadAllData() so Clerk Pro web users get initial data load (was only primed in primeVisiblePanelData, missing from the general reload path) P3 — Removed stale CONVEX_SITE_URL and VITE_CONVEX_SITE_URL from docs/authentication.mdx env vars table (neither is referenced in codebase) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: add isProUser import, populate PREMIUM_RPC_PATHS, and fix bearer token auth flow - Added missing isProUser import in App.ts (fixes typecheck) - Populated PREMIUM_RPC_PATHS with stock analysis endpoints - Restructured gateway auth: trusted browser origins bypass API key for premium endpoints (client-side isProUser gate), while bearer token validation runs as a separate step for premium paths when present Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(gateway): require credentials for premium paths + defer free-tier enforcement until auth ready P0: Removed trusted-origin bypass for premium endpoints — Origin header is spoofable and cannot be a security boundary. Premium paths now always require either an API key or valid bearer token. P1: Deferred panel/source free-tier enforcement until auth state resolves. Previously ran in the constructor before initAuthState(), causing Clerk Pro users to have their panels/sources trimmed on every startup. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(auth): apply WorldMonitor design system to Clerk modal Theme-aware appearance config passed to clerk.load(), openSignIn(), and mountUserButton(). Dark mode: dark bg (#111), green primary (#44ff88), monospace font. Light mode: white bg, green-600 primary (#16a34a). Reads document.documentElement.dataset.theme at call time so theme switches are respected. * fix(auth): gate Clerk init and auth widget behind BETA_MODE Clerk auth initialization and the Sign In header widget are now only activated when localStorage `worldmonitor-beta-mode` is set to "true", allowing silent deployment for internal testing before public rollout. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(auth): gate Clerk init and auth widget behind isProUser() Clerk auth initialization and the Sign In header widget are now only activated when the user has wm-widget-key or wm-pro-key in localStorage (i.e. isProUser() returns true), allowing silent deployment for internal testing before public rollout. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(data-loader): replace stale isProUser() with hasPremiumAccess() loadMarketImplications() still referenced the removed isProUser import, causing a TS2304 build error. Align with the rest of data-loader.ts which uses hasPremiumAccess() (checks both API key and Clerk auth). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(auth): address PR #1812 review — P1 security fixes + P2 improvements P1 fixes: - Add algorithms: ['RS256'] allowlist to jwtVerify (prevents alg:none bypass) - Reset loadPromise on Clerk init failure (allows retry instead of permanent breakage) P2 fixes: - Extract PREMIUM_RPC_PATHS to shared module (eliminates server/client divergence risk) - Add fail-fast guard in convex/auth.config.ts for missing CLERK_JWT_ISSUER_DOMAIN - Add 50s token cache with in-flight dedup to getClerkToken() (prevents concurrent races) - Sync Clerk CSP entries to index.html and tauri.conf.json (previously only in vercel.json) - Type clerkInstance as Clerk instead of any Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(auth): clear cached token on signOut() Prevents stale token from being returned during the ≤50s cache window after a user signs out. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Sebastien Melki <sebastien@anghami.com> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: Sebastien Melki <sebastienmelki@gmail.com> |
||
|
|
880c8dfdfd |
feat(community): add Discord link to dashboard (#1884)
* feat(community): add Discord link to dashboard footer and community widget - CommunityWidget: URL → discord.gg/re63kWKxaz - preferences-content: discussion link → Discord - panel-layout footer: add Discord link - en.json: "Join the Discussion" / "Open Discussion" → "Join Discord" * refactor(community): replace Discussions with Discord in all footers * fix(community): rotate dismissed key + update all locales for Discord rollout - Bump DISMISSED_KEY to wm-community-dismissed-v2 so users who dismissed the old GitHub Discussions promo see the new Discord invite - Update joinDiscussion/openDiscussion in all 20 non-English locales to "Join Discord" (proper noun, same in all languages) |
||
|
|
ba2117353e |
feat(community): add Discord link to footer (#1882)
* feat(community): add Discord link to footer across pro, blog, and docs Adds https://discord.gg/re63kWKxaz to: - pro-test/src/App.tsx — main Footer component and enterprise page footer - blog-site/src/layouts/Base.astro — site-wide blog footer - docs/docs.json — Mintlify socials icon + Community footer links section * docs(readme): add Discord badge to header badges |
||
|
|
987ed03f5d |
feat(webcams): add webcam map layer with Windy API integration (#1540) (#1540)
- Webcam markers on flat, globe, and DeckGL maps with category-based icons - Server-side spatial queries via Redis GEOSEARCH with quantized bbox caching - Pinned webcams panel with localStorage persistence - Seed script for Windy API with regional bounding boxes and adaptive splitting - Input validation (webcamId regex + encodeURIComponent) and NaN projection guards - Bandwidth optimizations: zoom threshold, bbox overlap check, 1s cooldown - Client-side image cache with 200-entry FIFO eviction - Globe altitude-based viewport estimation for webcam loading - CSP updates for webcam iframe sources - Seed-meta key for health.js freshness tracking |
||
|
|
d36263d996 | style: add Status page link to all footers (#1498) | ||
|
|
8174be951d |
feat(docs): Mintlify SEO metatags and changelog integration (#1495)
* style(docs): add OG image and SEO metatags for Mintlify Sharing docs links showed generic meta from the main site. Add seo.metatags to docs.json with OG image, site name, and Twitter card configuration. * feat(docs): add Mintlify changelog with Update components and RSS Convert CHANGELOG.md into Mintlify-native changelog page using <Update> components with tag filtering and RSS feed support. All 27 versions converted with categorized tags for filtering. |
||
|
|
e23f1cf85b |
docs: add dedicated license page with anti-rebranding and enforcement sections (#1490)
Extract license content from contributing.mdx into its own first-class docs/license.mdx page. Add prominent warnings about rebranding/renaming being prohibited without a commercial license, an enforcement section, and expanded commercial use restrictions. Update README.md license section to reflect the dual-license model (AGPL-3.0 for non-commercial, commercial license required for business use). Previously it incorrectly stated commercial use was allowed under AGPL alone. Update cross-references in documentation.mdx and getting-started.mdx to point to the new /license page. |
||
|
|
1f38dea225 |
docs: restructure documentation into focused, navigable pages (#1465)
* docs: restructure documentation into focused, navigable pages (#docs-reorg) Break the 4096-line documentation.mdx monolith into 13 focused pages organized by feature area. Reorganize Mintlify navigation from 5 generic groups into 7 feature-based groups. Move Orbital Surveillance from Infrastructure to Map Layers where it belongs. - Extract: signal-intelligence, features, overview, hotspots, CII, geographic-convergence, strategic-risk, infrastructure-cascade, military-tracking, maritime-intelligence, natural-disasters, contributing, getting-started - Append to: architecture.mdx (9 sections), ai-intelligence.mdx (3 sections) - Fix legacy .md links in map-engine.mdx, maps-and-geocoding.mdx - Slim documentation.mdx to an 80-line index/hub page - Eliminate duplicate content that caused repeated headings * fix(docs): remove duplicate H1 headings from all Mintlify pages Mintlify auto-renders the frontmatter `title` as an H1, so having `# Title` in the body creates a doubled heading on every page. Remove the redundant H1 (and repeated description lines) from all 31 .mdx files. |
||
|
|
dce6b77b27 |
fix(docs): remove invalid colors.anchors from Mintlify config (#1464)
Mintlify v2 schema rejects colors.anchors as unrecognized, blocking deployment validation. Added in #1463 but not a valid schema key. |
||
|
|
2a7d7fc3fe |
fix: standardize brand name to "World Monitor" with space (#1463)
Replace "WorldMonitor" with "World Monitor" in all user-facing display text across blog posts, docs, layouts, structured data, footer, offline page, and X-Title headers. Technical identifiers (User-Agent strings, X-WorldMonitor-Key headers, @WorldMonitorApp handle, function names) are preserved unchanged. Also adds anchors color to Mintlify docs config to fix blue link color in dark mode. |
||
|
|
878e30c371 |
style(docs): align Mintlify header/footer with site design (#1455)
* style(docs): align Mintlify header/footer with site design system - Navbar: Blog, Dashboard, Pro, GitHub (matching site header) - Primary CTA: "Get Early Access" green button linking to /pro#waitlist - Colors: switch from blue (#3b82f6) to green (#4ade80) accent - Footer: Dashboard, Pro, Blog + Community (GitHub, Discussions, X) - Add X/Twitter social link - Normalize all URLs to www.worldmonitor.app - Name simplified to "World Monitor" (matching site branding) * feat: add Docs link to dashboard, blog, and pro navigation Add link to /docs across all site surfaces: - Blog header nav and footer - Dashboard footer nav - Pro page footer (main + enterprise) |
||
|
|
caa3e9f82f |
fix(docs): rename doc files to lowercase for Mintlify (#1451)
* fix(docs): rename doc files to lowercase kebab-case for Mintlify Mintlify serves pages at lowercase URLs. Uppercase filenames caused 404s on the Documentation tab. Renames all 18 doc files, updates docs.json references, and fixes internal cross-links. * fix(docs): rename .md to .mdx for Mintlify compatibility Mintlify expects .mdx files. Plain .md files were not being found, causing 404s on all documentation pages. * feat(docs): add navbar links and footer with site variants - Navbar: Live App, Tech, Finance, Blog links + GitHub CTA - Footer: World Monitor variants + Resources columns - Logo links back to worldmonitor.app |
||
|
|
f292282ff7 |
fix(docs): add required theme field to Mintlify docs.json (#1450)
* fix(docs): add required theme field to Mintlify docs.json Mintlify v2 requires a theme discriminator. Without it, deployment fails with "Invalid discriminator value" error. * fix(docs): migrate docs.json to Mintlify v2 schema - navigation: object with tabs/groups instead of array - Remove colors.background (unrecognized in v2) - topbarLinks/topbarCtaButton → navbar - footerSocials → footer.socials - openapi: single string per group instead of array - Split docs into Documentation + API Reference tabs |
||
|
|
3d4c2fbdf4 |
chore(docs): trigger Mintlify deployment (#1449)
Trivial name change to force Mintlify GitHub App to detect docs changes after monorepo setting was updated in the dashboard. |
||
|
|
33a423b87f |
fix(docs): rename mint.json to docs.json for Mintlify v2 (#1446)
Mintlify deprecated mint.json in favor of docs.json. The dashboard expects docs.json to exist in the configured directory. |