Back to work

BlockLens

A crypto research tool that reads as one document per asset, and never lets a generated sentence sit next to a measured number without saying which is which.

Category
Crypto Research Intelligence
Type
Personal Project
Year
2026
Status
Deployed
Role
Solo Developer
Technologies
Next.js, React, TypeScript, Tailwind CSS, PostgreSQL, Prisma, LLM APIs
Index
02 / 05
A Bitcoin research dossier: price and 24-hour change, market cap, volume, circulating supply and distance from all-time high, a 30-day price chart, a seven-part contents list from Market to Interpretation, and a risk profile scoring liquidity, market size and volatility.

01Overview

BlockLens is a crypto research tool. Every asset opens as one continuous document — market structure, on-chain activity, tokenomics, project, events, risk, and an AI reading — rather than a grid of widgets behind tabs. It is a personal project, deployed and running on live data from CoinGecko, Alchemy, DeFiLlama and a set of news feeds.

02Problem

Most crypto tools answer one question well — what is the price — and leave the rest to a dozen browser tabs. The harder problem is that they hand you a confident paragraph without saying which part was measured, which part was calculated, and which part a model wrote. Once those three are mixed into the same voice, you cannot tell what you actually know.

03Approach

Two decisions. First, make the asset page a document you read top to bottom instead of a dashboard you assemble; nothing important sits behind a tab. Second, keep facts, signals and interpretation visibly apart — measured values in mono, derived readings in the interface face, generated argument in an italic serif. The typography carries the distinction, so it is visible before a word is read.

04System

Data flows one direction: provider API → adapter → service interface → normalisation → a server-only read layer that caches and wraps everything in a DataResult envelope → the UI. Components never call a provider. Each of the seven domains is an interface plus adapters plus a factory, so swapping CoinGecko for something else is one file and a switch. The envelope is the part that matters: a read is either ok with its provenance attached, or explicitly unavailable — which is why a failed provider blanks a section rather than filling it with a remembered number.

One direction only: provider → adapter → interface → read boundary → UI. Hover a component for detail.
  1. 01

    Surface

    • Dossier/research/[symbol] — one continuous document per asset: market, on-chain, tokenomics, project, events, risk, interpretation.
    • NewsFeed and article routes. An article resolves out of the cached provider window; nothing is written to the database.
    • Search · WatchlistThe client islands: search console, watchlist controls, contents tracker, account forms. Everything else is a server component.
  2. 02

    Boundary

    • server/dataThe only code that touches the services. Caches per endpoint and wraps every read in a DataResult — ok with provenance, or explicitly unavailable. Marked server-only, so a client import fails the build.
  3. 03

    Services

    • Market · On-chain · NewsDomains that wrap an external provider. Each is an interface plus adapters plus a factory; on-chain and news compose two sources into one reading.
    • Risk · TokenomicsComputed in the app, not bought. Seven scored dimensions — liquidity, market size, volatility, drawdown, supply overhang, position versus high, on-chain usage — each printing the arithmetic it came from.
    • AI synthesisReads the figures already on the page and returns an argument, labelled as generated. Unreachable means the section says so rather than substituting prose.
  4. 04

    Providers

    • CoinGecko · Alchemy · DeFiLlamaMarket data, block-level chain readings and DeFi metrics. DeFiLlama needs no key at all; without an Alchemy key the block-level readings are omitted rather than faked.
    • RSS · GNews · OpenAINews feeds normalised into one article shape with duplicates collapsed, and the model behind the interpretation section.
SurfaceServer components fetch once and pass data down. Client components exist only where there is real interaction — the price chart, the search console, the contents tracker, the watchlist controls and the forms.
Read boundarysrc/server/data is the only code that touches the services, and it is marked server-only so an accidental client import fails the build rather than shipping a key to the browser.
ServicesSeven domains behind interfaces. Market, on-chain and news wrap external providers; risk and tokenomics have no provider at all and are computed from data already held.
PersistencePostgres through Prisma holds accounts, sessions, watchlists and research history. The news routes deliberately store nothing — a slug is a pure function of the headline and URL.

05Interface

The asset page is a single scroll with a contents tracker rather than tabs, so the order of the argument is fixed and nothing important is hidden. Figures are set in mono and structural labels are too, which is what makes the interface read technical rather than decorative. Risk meters state their reading in words as well as colour, and a derived figure says next to the number that it was derived. There is no canvas and no 3D anywhere in the product — the backdrop is two CSS grids and one drifting light.

06Build

  • A DataResult envelope on every readA failed provider must never be papered over with an invented number, so 'unavailable' is a state the interface renders rather than an exception the page swallows. Provenance travels with the value so a view can say where a figure came from.
  • Compute risk rather than source itNo provider sells a risk score worth trusting. Each dimension is derived from data already held and prints its own arithmetic, and a composite is refused below three computable dimensions because it would be more confident than the evidence supports.
  • server-only on the read and service layersComponents never call a provider. An accidental client import fails the build instead of shipping an API key to the browser, and no key is ever read through a NEXT_PUBLIC_ variable.
  • News slugs as a pure function, with no stored rowA slug is a readable stem plus an FNV-1a hash of the canonical URL, so it is stable across requests and unique even when two outlets run the same headline. An article that ages out of the cache window returns a 404 that says exactly that — which is why the feature needed no migration.

07Current Status

Deployed on Vercel and running on live providers. The landing page is public; the research dossier, news and watchlist sit behind sign-in. Market data, DeFi metrics and news work with no provider key at all — a key only widens coverage or raises a rate limit — while Alchemy and OpenAI degrade to an explicit unavailable state rather than a fallback. Some things are deliberately absent: vesting schedules and holder distributions, because nothing in this stack reports them honestly. There are no users beyond my own account, and nothing here is investment advice.