GEM HUNTING ← live board
GEM HUNTING · Reference · Architecture + Data Model

Low-Cap Social Score Dashboard

The job isn't measuring hype — it's separating authentic signal from astroturf and cross-checking social against on-chain reality. Two data lineages run in parallel and converge at the scoring engine, where divergence between them becomes the actual edge. That duality is color-coded throughout.

On-chain Social Scoring Alerts / Risk tap to isolate a lineage
I

Component Architecture

L0Discovery & Ingestion Streaming + polled collectors, one worker per source. Push raw payloads to the bus.
On-chain track
New-pair listeners pump.fun · Raydium · Uniswap logs Market pollers Birdeye · Dexscreener RPC / mempool Helius Geyser · Alchemy Holder + LP fetch Security scan GoPlus · RugCheck
L1Ingest Bus / Stream Decouples ingestion from processing and absorbs launch-time bursts (a single tweet can 50× volume in minutes).
Kafka / Redpanda Redis Streams NATS JetStream topics: onchain.* · social.* · dead-letter
L2Processing & Enrichment Stateless consumer pools. This is where raw noise becomes trustworthy features.
On-chain enrichment
Top-holder concentration LP depth + lock resolve Dev-wallet tracking Honeypot / tax verdict Mint / freeze authority
Shared rollup
Interval aggregation 1h · 4h · 24h Velocity + acceleration Cohort assignment
L3Scoring Engine convergence The only layer that reads both lineages. Baselines against the token's own history and a peer cohort, then computes divergence.
Composite score auth · momentum · community · KOL · on-chain risk Cohort percentile Divergence detection social ⇄ volume ⇄ price Signal / alert generation
L4Storage Split by access pattern: relational core, append-only time-series, and a hot cache for the live view.
Postgres tokens · accounts · KOLs · alerts Timescale / ClickHouse all *_snapshot + mentions Redis latest scores · leaderboards · counters Object store raw payload audit (optional)
L5Serving Query for the app, push for live updates, dispatch for outbound alerts.
REST + GraphQL API WebSocket / SSE live scores Alert dispatcher Telegram · Discord · webhook
L6Frontend Every view surfaces both lineages side by side — the divergence is the story.
Leaderboard / watchlist Token detail score breakdown Social ⇄ on-chain divergence chart KOL call feed Holder / LP panel Alerts feed Cohort explorer
Cross-cutting
Orchestrator Temporal · Airflow · cron Rate-limit + API-key manager Secrets / config Observability metrics · logs · traces Backfill / replay
II

Data Model

POSTGRES Relational core — entities that change slowly and need joins / constraints.
tokenroot entity
PKiduuid
chainenum
UQcontract_addresstext
symbol · name · decimalstext · int
launch_platformenum
launch_at · first_seen_attimestamptz
statusenum
socialsjsonb
social_accountre-profiled on TTL
PKiduuid
platformenum
UQhandle(platform,handle)
follower · following_countint
created_attimestamptz
bot_scorefloat 0–1
authenticity_scorefloat 0–1
is_kol · kol_tierbool · int
last_profiled_attimestamptz
kol_callpredictive log
PKiduuid
FKaccount_id→ social_account
FKtoken_id→ token
ts · tiertimestamptz · int
paid_suspectedbool
price_at_call · mcap_at_callnumeric
use: snapshot entry price so KOL hit-rate is measurable later.
cohortpeer baseline
PKiduuid
nametext
definitionjsonb
chain·age·mcap·platform
refreshed_attimestamptz
token_cohortjoin
FKtoken_id→ token
FKcohort_id→ cohort
alertsignal record
PKiduuid
FKtoken_id→ token
IXtstimestamptz
typeenum
velocity_spike · divergence · bot_surge · kol_call · lp_unlock · concentration
severityint
payload · acknowledgedjsonb · bool
TIMESCALE / CLICKHOUSE Append-only hypertables, partitioned by time and keyed on (token_id, ts).
market_snapshothypertable
FKtoken_id · tscomposite
price_usd · mcap · fdvnumeric
liquidity_usdnumeric
vol_1h · vol_24h · txns_1hnumeric · int
holder_countint
top10_pctfloat
lp_locked · lp_unlock_atbool · ts
social_snapshothypertable · per interval
FKtoken_id · ts · intervalcomposite
mentions · unique_authorsint
mention_velocityfloat
mention_accelfloat · 2nd deriv
new_acct_ratiofloat
avg_bot_scorefloat
weighted_engagementfloat
kol_mentions · sentiment_avgint · float
community_snapshothypertable
FKtoken_id · ts · platformcomposite
members · member_growthint · float
msg_velocityfloat
active_speakersint
active_speaker_ratiofloat
mentionhigh-volume · downsample
PKiduuid
FKtoken_id · account_id
platform · post_id · ts
kindoriginal·reply·quote
likes · reposts · replies · viewsint
sentiment · engagement_scorefloat
text_hashbytes · dedup
retention: keep raw N days, then roll into social_snapshot.
score_snapshothypertable · engine output
FKtoken_id · tscomposite
authenticity · momentumfloat
community · kolfloat
onchain_riskfloat
social_score · composite0–100
cohort_pctfloat
divergencejsonb
REDIS Hot layer — the live dashboard reads here, never from cold storage.
score:latest:{token_id}hash
composite + all subscoresTTL refresh
leaderboard:{cohort}sorted set
member=token_id, score=compositeZRANGE
counters:{token}:{interval}rolling
live mention counterswindowed
profile:{account_id}cache
bot / auth scoreavoid re-scoring
Relationships
token1 → ∗   market · social · community · score snapshots, mention, alert, kol_call
social_account1 → ∗   mention, kol_call
token ⇄ cohort∗ → ∗   via token_cohort
Derived metrics — computed by the engine, not stored raw
mention_velocity=Δ mentions / Δt Rate beats level on micro caps: 3 → 40/hr is the signal; 200 steady is a dead pump.
mention_accel=Δ velocity / Δt The second derivative is where the early edge lives — is the growth itself speeding up?
author_diversity=unique_authors / mentions 100 mentions from 4 accounts ≠ 100 from 80. Low ratio = coordinated.
social_divergence=social_pct − vol_24h_pct Social spiking while real buy volume lags is the classic astroturf tell.
talkers_to_holders=active_speakers / holder_count Chatter running far ahead of real ownership = manufactured community.
mentions_to_holders=mentions / holder_count Same idea, mention-weighted — flags social outrunning the actual holder base.