Commit Graph

125 Commits

Author SHA1 Message Date
martbost 65b963b39b Persist admin sessions across redeploys
Sessions now load from and save to sessions.json in the data volume
(0600, atomic write, expired entries pruned on save), so a redeploy no
longer logs the admin out. Verified: session cookie survives a full
server restart.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-13 15:04:22 -05:00
martbost 6a9cd96b8c Qualified dashboards promote the next unqualified position in their leg
Instead of only pointing at the team rotator, a qualified member's share
card now runs the moving-link wave automatically: breadth-first,
left-to-right, the first position below them with fewer than 2 directs
becomes "next in line" — their QR, page link, and join CTA all carry
that position's ID. When it qualifies, the card rotates to the next one.
Falls back to the team rotator when the whole leg is qualified.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-13 14:58:31 -05:00
martbost 350d50798f Member dashboard: drill-down tree, list view, legend, and strategy-aware referral tool
- "Your team" now covers the member's FULL leg with click-to-drill
  pyramid, breadcrumb, and a list-view toggle (mirrors the admin matrix).
- Legend under both the member tree and admin matrix explaining the
  qualified checkmark, tier badges, and downline rollup.
- "Share this position" card: while under 2/2 it's a personal recruiting
  tool — per-member QR (vendored qrcode-generator, CSP-safe), copy link,
  and a join CTA carrying the member's ID as sponsor. At 2/2 the page
  automatically retires the link and redirects sharing to the team
  rotator, so personal referrals can't undermine the moving-link
  strategy.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-13 14:53:06 -05:00
martbost 9f8898d2bd Add public member dashboard at /my/:id
Members enter their on-chain ID (or follow a /my/46-style link) and see
their own position: tier/level/directs/earnings facts, their subtree
pyramid with downline rollups and open slots, classified payment
history, and lineage to root — all chain-derived data only, none of the
admin operational config. Public endpoint /api/public/member is cached
(120s) and rate-limited (20/min/IP). Linked from the public footers.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-13 14:35:05 -05:00
martbost e332a4f1c2 Allow renaming a sponsor from the queue
The name in the Sponsor Queue is now a click-to-rename control (pencil
appears on hover), using the existing PATCH endpoint; server trims and
caps the name.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-13 13:47:07 -05:00
martbost 0f5f821b39 Email the admin a copy of every team-build alert
New config teamAlertEmail: the same team-gated on-chain events that post
to Telegram (registration, upgrade, payout at/below teamRootId) also go
to this address via SendGrid, so deep-leg activity surfaces even away
from Telegram.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-13 13:12:33 -05:00
martbost accd869c12 Default payment-email sender to marketingwithmarty.com
Both marketingwithmarty.com and mybrandedvoice.com are SendGrid
DKIM-authenticated; Marty's sending identity is marketingwithmarty.com,
so the default from and the admin label now reflect that.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-13 13:10:41 -05:00
martbost e3f07057d9 Send automatic "you've been paid" emails via SendGrid
When the chain tail sees a payout to a member whose sponsor record has a
contact email, the site emails them the amount, source, and Polygonscan
link (plain text — deliverability). SendGrid key is pasted in a new
admin panel (stored in the data volume, like the OpenRouter key) or set
via SENDGRID_API_KEY. From address defaults to no-reply@mybrandedvoice.com
— the domain SendGrid is DKIM-authenticated for — and is editable in the
same panel. Not gated on teamRootId; any member with an email on file.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-13 13:03:26 -05:00
martbost 6b17419646 Add sponsor contact emails and Telegram team-build activity alerts
Sponsors can carry an optional contact email (Add Sponsor form, ✉ inline
edit in the queue, shown under the name). New config teamRootId: any NEW
on-chain event at or below that member ID — registration, upgrade, or
payout seen by the live tail — posts to the Telegram group topic, with
the tx link and the sponsor's contact email when one is on file.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-13 12:57:51 -05:00
martbost 7c41499312 Add on-chain payment proof: live payout feed, ID verification, admin lineage tools
New chain.js reads the RM Circle contract (0x33Bd…2DAF, Polygon) via free
public RPCs — no API keys. Daily snapshot rebuilds complete payout history
from getIncomeHistory (log providers prune old history), and a 60s
eth_getLogs tail catches new payouts with tx hashes, upgrade context, and
passed-over upline IDs.

- Bridge page: "Live payment proof" feed + timed toast pop-ups for payouts
  seen in the last 15 min, every row linking to Polygonscan.
- /start: same toasts; ID submissions are now verified against the contract
  (result shown to the member, in Telegram notify, and in admin).
- Admin: on-chain member lookup (lineage to root, directs, matrix children,
  full income history) and a collapsible full matrix tree view.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-13 10:25:07 -05:00
martbost 89a84aa7ca Allow public pages to render in safelist/traffic-exchange iframes
Framing was blocked site-wide (X-Frame-Options DENY + frame-ancestors
none), so safelists and traffic exchanges showed a blank panel. Public
pages now send frame-ancestors *; admin.html keeps the strict lockdown.
Join button opens the dApp in a new tab so it escapes the exchange
iframe (dApps typically refuse to render framed).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-13 08:37:56 -05:00
martbost fe357dd361 Use escaped control-char class in memberName sanitizer
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-12 13:59:15 -05:00
martbost e5eefdfc61 Require name or Telegram handle on member ID submission
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-12 13:57:34 -05:00
martbost 2b40dc70c8 Support posting member submissions to a Telegram forum topic
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-12 13:46:25 -05:00
martbost 89f27b89a2 Close the conversion loop: member ID submission with Hermes Telegram notify
- Start page step 6 is now a bold gold-highlighted "Submit your NEW RM
  Circle ID" form with larger step numbers throughout; captures the
  sponsor the visitor was shown at join time.
- POST /api/public/submit-id: validates numeric ID, dedupes, stores on
  the volume, records a per-source "purchase" analytics event, fires a
  BeMob postback (txid=purchase-<clickid>) to close paid campaigns, and
  posts the new ID + sponsor + source to the configured Telegram chat
  (MB Hermes pattern). Rate-limited.
- Admin: Member ID Submissions table, "Confirmed joins" tile, and
  Telegram bot token / chat ID settings.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-12 13:30:53 -05:00
martbost 63e8b4cdd0 Add paid-traffic tracking: clickid capture and BeMob conversion postback
- track.js stores ?clickid= (or ?cid=) for the session; rides through
  bridge -> start navigation alongside the existing source attribution.
- Join click (the conversion) sends the clickid; server fires a
  fire-and-forget S2S postback to the admin-configured BeMob postback
  URL (cid + txid=join-<clickid>, payout 0) and counts successes per
  source in analytics.
- New admin setting: BeMob postback URL (server-side only, not exposed
  in public config).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-12 11:26:34 -05:00
martbost c1ec687768 Let admins enable AI chat by pasting an OpenRouter key in the admin panel
Key is stored on the persistent volume (0600, never in git), read
dynamically per request, maskable status only in admin state, and
clearable to fall back to built-in answers. OPENROUTER_API_KEY env var
still takes precedence if ever set.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-12 09:17:39 -05:00
martbost ca5605e056 Add AI chat backend via OpenRouter with knowledge-base fallback
POST /api/public/chat proxies to OpenRouter (model from
OPENROUTER_MODEL, default deepseek/deepseek-v4-flash:nitro) with a
system prompt built from live site config, sponsor queue, and strict
guardrails (no income claims, seed-phrase warnings, Telegram fallback).
Rate-limited per IP. Without OPENROUTER_API_KEY set, or on any API
error, the widget transparently falls back to the built-in knowledge
base, so the chat always works.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-12 08:47:02 -05:00
martbost ec2091631e Add /training page with four self-hosted walkthrough videos
- Videos loudness-normalized to -16 LUFS (originals were ~-33 LUFS).
- Static file serving rewritten to stream with HTTP Range support so
  video seeking works; .mp4/.webm MIME types added.
- Training nav links on homepage and /start, plus a first-time callout
  on /start; training page views tracked per source in admin analytics.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-12 07:32:59 -05:00
martbost a32a710c80 Make video embed responsive with size fallback; stop caching CSS/JS
CSS and JS are now served no-cache like HTML so style/script updates
apply on normal refresh instead of waiting out a 1-hour browser cache.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-11 10:18:30 -05:00
martbost 2890dc2f1b Embed team build walkthrough video on homepage; allow YouTube in CSP
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-11 10:14:23 -05:00
martbost 4115d3a920 Add simple traffic analytics with source attribution and conversion funnel
- track.js captures first-touch source per session (utm_source/src param
  or external referrer domain) and logs bridge/start page views.
- Join clicks now carry the source; all events aggregate per-source in
  data/analytics.json on the persistent volume.
- Admin: new Traffic & Conversions card with funnel totals (bridge ->
  start -> join click rates) and a per-source breakdown table.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-11 08:07:41 -05:00
martbost 241bc2060d Serve .webp with correct image/webp content type
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-11 07:41:51 -05:00
martbost 2b1f526bef Add inline level editing in admin queue and roadmap infographic on start page
- Admin: Level column is now a dropdown of the 8 premium levels (Scintilla
  through Corona), saving immediately via PATCH; server validates levels.
- Start page: RM Circle Team Build Roadmap graphic above the fold with
  Crypto Team Build Network attribution (compressed to 198KB WebP).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-11 07:40:00 -05:00
martbost 76bd288bf6 Initial commit: RM Circle team sponsor router (bridge page, /start, /admin, Docker)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-11 07:04:08 -05:00