project-architecture
How the angel-investments codebase is laid out — tech stack, data files, page inventory, navigation, theming, view modes, file naming, tests, and how to add a company, page, chart, theme or translation. Use when orienting in the repo or before adding or moving code, data files, pages, themes or translations.
- Source file
.claude/skills/project-architecture/SKILL.md
Project architecture
Moved out of CLAUDE.md on 2026-10-11 (owner: keep CLAUDE.md thin). Parts of it
predate the static public site; for what production actually serves, read the
production-deployment skill.
What This Project Is
A public-facing portfolio dashboard for angel investor Sahin Boydas (sahin.io). It tracks the public portfolio (234 companies as of 2026-10-09; the count lives in the data, see "Counts" below) with rich data visualizations, founder profiles, co-investor analysis, and investment intelligence. Built as a React SPA with static JSON data files — no backend database for portfolio data.
Tech Stack
- Frontend: React 19 + TypeScript + Tailwind CSS 4 + shadcn/ui
- Router: wouter (with base path
/angel-investments) - Backend: Express 4 + tRPC 11 (for auth/user features only)
- Database: TiDB/MySQL via Drizzle ORM (user accounts only, not portfolio data)
- Charts: Recharts, D3.js (force graphs, sankey, geo maps)
- Build: Vite 7
- i18n: react-i18next (English + Turkish)
Architecture
All portfolio data lives in static JSON files under client/public/ and client/src/data/. There is no API for portfolio data — everything is client-side. The tRPC backend handles only authentication and user management.
Key Data Files
| File | What It Contains |
|---|---|
client/public/portfolio-data.json |
Core public companies (slug, name, market, stage, valuation, logo, exitStatus) |
client/public/investment-intelligence.json |
Enriched data (invest_year, exit_status, market_cap, competitors) |
client/public/enriched-company-data.json |
Deep company profiles (funding_rounds, founders, descriptions) |
client/public/vc-data.json |
Co-investor VC firms and their portfolios |
client/public/secondary-market-data.json |
Pre-IPO secondary market trading data |
client/public/company-locations.json |
Geographic coordinates for map |
client/public/news-items.json |
Portfolio news feed |
client/src/data/portfolioData.ts |
TypeScript data loader + Company interface |
client/src/data/founders-data.json |
Founder profiles with social links |
Page Inventory (30+ pages)
Core: Home, InvestmentThesis, StageComparison, StatusPage, CoInvestors, Sectors Visualizations: Landscape, SectorHeatmap, GeoMap, Timeline, PortfolioNetworkGraph, InvestmentSankey, MarketTimingHeatmap People: Founders, FounderDetail, FounderNetwork, FounderTracker Research: CompanyIntelligence, CompanyDetails, CompanyMetrics, CompanyComparison, CompanyCompare, CompetitorRadar, ExitReadiness, ExitScenarioModeler VC Deep Dives: A16zPortfolio, SequoiaPortfolio, AccelPortfolio, FoundersFundPortfolio, YCPortfolio, VCLogos Content: NewsFeed, NewsDetail, Lessons, SecondaryMarket
Navigation Structure
The menu (groups Explore, Insights, Stories, Research; each page's label, title and description) is content/shared/navigation.yaml, built by shared/publicNavigation.ts and shown by the static header (server/publicChrome.ts), SiteSidebar.tsx and MobileSectionNav.tsx. Chrome copy is content/shared/chrome.yaml; run node scripts/sync-site-copy-module.mjs after editing either (page-content-yaml skill).
Theming
InvestorThemeContext provides 10+ theme presets (Default, Midnight, Forest, etc.). All pages use theme.colors.* for dynamic theming. ThemeSwitcher in navbar.
View Modes
Human mode (normal UI) and Agent mode (structured markdown for AI consumption). Toggled via ViewModeContext.
Common Questions You Might Ask
How do I add a new company?
Add it to client/public/portfolio-data.json. Optionally add enriched data to investment-intelligence.json and enriched-company-data.json.
How do I add a new page?
Public pages are no longer client/src/pages/ + App.tsx routes. Follow the
new-react-page skill (file checklist: props builder in server/publicPages/,
client/src/publicPages/*Page.tsx + *Types.ts + CSS, registration in
types.ts, PublicReactPageView.tsx, components.client.ts/components.server.ts,
the route in server/publicReactPages.ts or server/reactPageRoutes.ts, copy
in content/pages/<page>.yaml, menu entry in content/shared/navigation.yaml,
then node scripts/sync-site-copy-module.mjs). Each page family has its own
page-* skill (index at https://sahin.io/angel-investments/skills-and-agents);
add routes: to it or server/page-skills-coverage.test.ts fails.
How do I add a new chart/visualization?
Use Recharts for standard charts (bar, line, pie, area). Use D3.js for force graphs, sankey, geo projections. Import theme colors from useInvestorTheme().
How do I update the data?
Use the airtable-manus-sync skill (Airtable Manus view only).
How do I add a new theme?
Add a new entry in InvestorThemeContext.tsx with all required color fields (background, foreground, card, border, primary, accent, etc.), and its name and description in content/shared/themes.yaml (gallery groups are there too), then node scripts/sync-site-copy-module.mjs.
How do I add translations?
Add keys to client/src/i18n/locales/en.json and tr.json. Use useTranslation() hook with t('key') in components.
Where are the VC logos?
Stored as URLs in vc-data.json. Company logos are in portfolio-data.json as URLs.
How does the secondary market data work?
secondary-market-data.json contains pre-IPO trading estimates. Loaded async via fetch in pages that need it (SecondaryMarket, InvestmentSankey).
File Naming Convention
- Pages: PascalCase (
CompanyCompare.tsx) - Components: PascalCase (
NavBar.tsx) - Data: kebab-case (
portfolio-data.json) - Contexts: PascalCase with Context suffix (
InvestorThemeContext.tsx)
Testing
Run pnpm test for vitest. Test files in server/*.test.ts. Frontend is manually tested via browser.