See it in action

The diary is the operational backbone of the tracker — every meeting, decision, and milestone logged in one place. Click "Diary" in the nav to see it.

Click the Diary tab in the nav above to see the diary view.

The heatmap shows you at a glance which companies are active and which have gone quiet. Below is how to build it.

Build it with Claude

If you've already built the Portfolio Tracker, the diary is an extension of the same codebase. If you're starting fresh, these prompts include everything you need.

1

Set up diary entries

Build the core component to fetch and display entries for a single company.

Prompt for Claude

"Build a CompanyDiary page component for my portfolio tracker. It should fetch a single company by ID along with all its diary entries from Supabase. Display a header with company name, status, category, and investment year. Below that, show the diary settings: update cadence, last update date, founder name and email, and internal notes (only visible to syndicate leads). Then render all entries in a timeline format, reverse chronological, with color-coded badges for each entry type (update=blue, funding=green, closed_round=purple, warning=red)."

2

Build the heatmap view

Add entry creation and wiring to the dashboard heatmap.

Prompt for Claude

"Add a 'New Entry' form to the CompanyDiary page. Only show it if the user is_syndicate_lead. Fields: date (default today), entry_type (dropdown: update, funding, closed_round, warning), title (text), body (textarea). On submit, insert into diary_entries via Supabase and refresh the timeline. The database trigger will auto-update last_update_date in company_diary_settings."

3

Add the company detail page

Link the heatmap cells to the company diary page.

Prompt for Claude

"On the Dashboard heatmap, make each company name a link to /company/:id which renders the CompanyDiary component. Add a back button on the CompanyDiary page that returns to the dashboard. When navigating from a heatmap cell, scroll to the entry for that month if possible."

4

Wire up auto-updates

Scope the investor view and set up database triggers.

Prompt for Claude

"Add investor scoping to the CompanyDiary page. Check if the current user is_syndicate_lead. If not, hide: internal_notes, founder_name, founder_email, and the new entry form. RLS already filters which companies they can see — this is just hiding the lead-only UI elements. Also add a header that says 'Your Portfolio' instead of 'All Companies' for investor users."

Deploy it

The diary deploys as part of the same React app as the portfolio tracker — they're routes in the same SPA. Same Cloudflare Pages setup, same GitHub repo, same auto-deploy pipeline.

Route structure / → Dashboard (heatmap + stats) /company/:id → CompanyDiary (timeline + settings) /login → Magic link auth

If you've already deployed the portfolio tracker, the diary is already there — it's just the company detail page. If you're starting from scratch, follow the deploy steps in the Portfolio Tracker guide.

Under the hood

Everything above gets you a working diary. Below is how it works — useful for customisation.

Entry types

Each entry has a date, a type, a title, and a body. The type determines how it shows up in the timeline and on the heatmap.

Entry types update — Regular portfolio update from the founder "Q1 revenue up 40%, expanding to 3 new markets" funding — Funding round activity "Series A term sheet from Lead VC, $8M at $35M pre" closed_round — A round that closed "Seed round closed, $2.1M total, 12 investors" warning — Something that needs attention "CTO departed, replacement search underway"

Auto-update trigger

One of the most useful pieces: a database trigger that automatically updates last_update_date whenever a new entry is created. This means overdue detection is always current without manual bookkeeping.

SQL trigger CREATE OR REPLACE FUNCTION update_last_diary_date() RETURNS trigger AS $$ BEGIN UPDATE company_diary_settings SET last_update_date = NEW.entry_date WHERE company_id = NEW.company_id AND (last_update_date IS NULL OR NEW.entry_date > last_update_date); RETURN NEW; END; $$ LANGUAGE plpgsql; CREATE TRIGGER diary_entry_update_date AFTER INSERT OR UPDATE ON diary_entries FOR EACH ROW EXECUTE FUNCTION update_last_diary_date();

This trigger fires on every insert or update to diary_entries. It only moves the date forward (never backward), so editing an old entry won't mess up the overdue calculation.

The company detail page

When you click into a company, you see its full diary — every entry in reverse chronological order, plus metadata like status, category, investment year, update cadence, and founder contact info. Internal notes (visible only to the syndicate lead) sit at the top.

What the company page shows

Header: Company name, status badge, category, investment year. Settings: Update cadence, last update date, founder name and email, internal notes. Timeline: Every diary entry with color-coded type badges, dates, and full body text. Entries are grouped visually — you can scan the colors to see the company's trajectory at a glance.

Making it yours

The diary we built for Raspberry Ventures tracks 27 companies with 83 entries. But the structure works for any size. A few ways to customize it:

Related reading

The diary and the portfolio tracker share the same database and follow the same pattern. See the Portfolio Tracker guide for the full context on how these tools connect, the database schema, and the Supabase + React + Cloudflare Pages pattern.