Back to all posts
Published 2026-05-122 min read

Why I Built a Decision Log Before I Built the Dashboard

The first feature of AlphaNode is not a chart. It's a forcing function that makes me write down what would prove me wrong.

build-in-publicinvesting

When I started AlphaNode, the obvious first build was a beautiful dashboard — moving lines, sector heatmaps, watchlist sparklines. Dashboards photograph well. They get clicks on X.

I shipped a Decision Log instead.

The pain that actually loses me money

Looking back at three years of trades, the ones that hurt the most were never bad ideas. They were ideas I never bothered to write down.

I would say to myself, "I'm buying NVDA because the silicon photonics cycle is inflecting." Six months later, NVDA is down 18%, the silicon photonics narrative is still alive, and I'm holding because I'm anchored. But what was the invalidation condition I would have written down? I never wrote one.

If you can't write down what would prove your thesis wrong, you don't have a thesis. You have a feeling.

What the form forces

Every entry in AlphaNode's Decision Log requires five fields:

  1. Ticker
  2. Action (Buy / Sell / Short / Cover / Hold)
  3. Sector
  4. Core thesis — the one-paragraph why
  5. Invalidation condition — the specific evidence that would kill this trade

The fifth field is the only one that matters. The Data Table even highlights it in a warning color so I can't pretend I didn't see it.

The technical implementation is boring

// Server Action — runs on Vercel, writes to Supabase
"use server";
export async function createDecision(input: DecisionInput) {
  const validated = decisionSchema.parse(input);
  await supabase.from("decision_logs").insert(validated);
  revalidatePath("/decision-log");
}

react-hook-form + zod on the client. A Server Action submits it to Supabase. revalidatePath re-renders the table. Total code: under 200 lines.

The behavior change in me, though — that's the whole point.

What's next

  • Phase 2: a closed_at column with a free-text post-mortem field. Did the invalidation condition trigger? If yes, did I sell, or did I rationalize?
  • Phase 3: weekly emails with "decisions older than 90 days you haven't reviewed."

If you have your own version of this, I'd love to hear how you structured it.