page-status-sectors-markets
Spec for the Status guide, the Sectors pages, the Sector Heatmap and the market profiles on sahin.io/angel-investments (/status, /status/{slug}, /sectors, /sectors/{slug}, /sector-heatmap, /market/{slug}). Use when building, rebuilding or changing any of these pages, their slugs, their copy or the data they group by.
- Source file
.claude/skills/page-status-sectors-markets/SKILL.md- Routes covered
/status/status/*/sectors/sectors/*/sector-heatmap/market/*
Status, sectors and markets pages
Routes
| URL | Route kind | Count today | Render |
|---|---|---|---|
| https://sahin.io/angel-investments/status | legacyFeature (menu page) |
1 | static shell + React status |
| https://sahin.io/angel-investments/status/{slug} | reactPage (family /status) |
20 | static shell + React statusDetail |
| https://sahin.io/angel-investments/sectors | legacyFeature |
1 | static shell + React sectors |
| https://sahin.io/angel-investments/sectors/{slug} | reactPage (family /sectors) |
37 | static shell + React sectorDetail |
| https://sahin.io/angel-investments/sector-heatmap | legacyFeature |
1 | static shell + React sectorHeatmap |
| https://sahin.io/angel-investments/market/{slug} | reactPage (family /market) |
37 | static shell + React marketDetail |
- Menu pages come from
content/shared/navigation.yaml(/statusin sectionexplore,/sectorsand/sector-heatmapininsights) →LEGACY_MENU_PAGESinshared/publicNavigation.ts→route(..., "legacyFeature", title)increateSeoRouteManifest()(server/seoRouteManifest.ts). Static body:renderLegacyFeaturePage(). - Families live in
FAMILIESinserver/reactPageRoutes.ts; slugs fromlistStatusDetailSlugs,listSectorDetailSlugs,listMarketDetailSlugs. Static body:renderReactShellPage(). scripts/generate-static.tsreplaces every shell body with the React page fromreactPageForRoute()(server/publicReactPages.ts).- Sector and market slugs both use
taxonomySlug()overcompany.market("AI / ML" →ai-ml), so the two families always have the same number of members (asserted inserver/seo-route-manifest.test.ts). Status slugs are the 20 fixedSTATUS_DEFINITIONSinserver/publicPages/status.ts. - URL rules:
public-url-conventions.
Files
| Page | Props builder | Component + types | CSS | Copy |
|---|---|---|---|---|
| /status | buildStatusProps in server/publicPages/status.ts |
client/src/publicPages/StatusPage.tsx, statusTypes.ts |
styles/status.css |
content/pages/status.yaml (page words), content/pages/statuses.yaml (every status's title, descriptions, criteria, implications, FAQ, category labels) |
| /status/{slug} | buildStatusDetailProps, statusDetailPageMeta in server/publicPages/statusDetail.ts |
StatusDetailPage.tsx, statusDetailTypes.ts |
styles/statusDetail.css |
content/pages/status-detail.yaml (meta = title/description templates) |
| /sectors | buildSectors in server/publicReactPages.ts |
SectorsPage.tsx, types in types.ts (SectorsPageProps, SectorSummary) |
shared rules in client/src/index.css (.ci-head, .sx-grid, .sx-bar, .sx-other) |
content/pages/sectors.yaml |
| /sectors/{slug} | buildSectorDetailProps, sectorDetailPageMeta in server/publicPages/sectorDetail.ts (reuses buildSectors) |
SectorDetailPage.tsx, sectorDetailTypes.ts |
styles/sectorDetail.css |
content/pages/sector-detail.yaml (pageTitle, description) |
| /sector-heatmap | buildHeatmapSectors in server/publicReactPages.ts |
SectorHeatmapPage.tsx, HeatmapSector in types.ts |
client/src/index.css (.hm-*, .tl-filters) |
content/pages/sector-heatmap.yaml (incl. trends, macro signals) |
| /market/{slug} | buildMarketDetailProps, marketDetailPageMeta in server/publicPages/marketDetail.ts |
MarketDetailPage.tsx, marketDetailTypes.ts |
styles/marketDetail.css |
content/pages/market-detail.yaml (pageTitle, description) |
Registration: each kind is in the PublicReactPage union in client/src/publicPages/types.ts, components.client.ts (lazy) and components.server.ts (serverPageComponents). CSS files are @imported from client/src/index.css. Components read copy through @/generated/copy/pages/<file> (regenerate with node scripts/sync-site-copy-module.mjs); builders read it with loadPageContent() (server/pageContent.ts).
Data inputs: the public portfolio (ctx.companies), research records via loadEnrichedRecords() (client/public/enriched-company-data.json, slug aliases in ENRICHED_SLUG_ALIASES), the sourced company value via sourcedValueUsd() / sourced() (server/publicCompanyValue.ts), logos via publicCompanyLogo().
Sections on the page
- /status: header (eyebrow, title, subtitle) → status cards grouped by the
statuses.yamlcategories, each with icon, color, short description and member count → per-status detail (criteria, implications, matching companies, related statuses). - /status/{slug}: back link → header → stats → criteria → implications → market distribution and company-value distribution (donut) → FAQ → companies carrying the status (or
empty) → related statuses → browse all. - /sectors: header → sector cards (count, share bar) sorted by count → "other" small sectors → expandable sector detail and table (companies sorted by sourced value, stage mix, funding raised).
- /sectors/{slug}: the /sectors view opened on one sector (expanded and scrolled into view), with its own title/description and links to other sectors.
- /sector-heatmap: header → summary tiles → view toggle and sort (
.tl-filters) → heat tiles per sector (trend: hot / warm / neutral / cooling frommacro) → table → detail panel. - /market/{slug}: header + link to the matching sector → headline stats → most funded companies → stage mix → funding vs company value bubbles → investors → every company in the market → compare with other markets.
SEO
- Menu pages:
<title>and description fromcontent/shared/navigation.yaml;/status,/sectors,/sector-heatmapmay instead take the hero intro fromcontent/pages/recovery-surfaces.yaml(RECOVERY_SURFACE_BY_PATH, unless listed inMENU_DESCRIPTION_FEATURES). JSON-LD:buildPageGraph({ kind: "legacyFeature", itemList })with the related links fromlegacyFeatureContextLinks()(category links for/sectorsand/sector-heatmap). - Families: title/description from each builder's
*PageMeta(YAML templates); breadcrumb from the familycrumb; JSON-LDbuildPageGraph({ kind: "reactPage" }). All members areindex(noindexingfunction), so all are in the sitemap and llms files. - Canonical:
https://sahin.io/angel-investments<path>viaheadSpec(). Head and schema details:seo-head-and-schema. /sectors/,/market/,/status/are inKNOWN_UNLINKED_FAMILIESinserver/public-link-graph.test.ts: they need not be linked from the hub.
Rules
- Status member counts must agree with
shared/portfolioStatus.ts(hasExitStatus,isActiveCompany); seeportfolio-counts-single-source. The public data records only Live / Acquired / Public / Failed; no company may be shown as "Realized". statuses.yamlandSTATUS_DEFINITIONSmust match one to one;buildStatusPropsthrows on a missing or extra status or category.- Company values: only the sourced value with its citation (
sourcedValueUsd,SourcedValueText); never research figures or sums of them. No present-tense "today" claims on value tiers (server/public-company-value.test.ts). - No private deal data on any of these pages:
private-data-boundary. - All words in YAML:
page-content-yaml. The heatmap's macro signals are curated copy insector-heatmap.yaml, not data.
Tests
server/seo-route-manifest.test.ts: 20/status/routes;/sectors/count equals/market/count; restricted-term checks on/status.server/public-react-document.test.ts:/statuskeeps its crawlable head and body inside the React root;buildSectorsputs every company in exactly one sector.server/portfolio-status-single-source.test.ts: /status card counts equal the shared status summary.server/public-company-value.test.ts: sourced-only values on/status,/status/1b-plus,/sectors,/sector-heatmap, sample/market/*and/sectors/*.server/public-link-graph.test.ts,server/legacy-redirects.test.ts.
Rebuild from scratch
- Confirm the three menu entries (path, label, title, description, section) in
content/shared/navigation.yaml; runnode scripts/sync-site-copy-module.mjs. - Write the copy files listed above under
content/pages/. - Status: define
STATUS_DEFINITIONS(slug, category, icon, color, matcher, related) inserver/publicPages/status.ts, matching viashared/portfolioStatus.ts; buildbuildStatusProps; thenstatusDetail.tswithlistStatusDetailSlugs(from the same props),buildStatusDetailProps,statusDetailPageMeta. - Sectors:
buildSectorsandbuildHeatmapSectorsinserver/publicReactPages.ts(group bycompany.market || 'Other');sectorDetail.tswithsectorDetailSlug = taxonomySlug. - Markets:
marketDetail.tswithlistMarketDetailSlugs,buildMarketDetailProps,marketDetailPageMeta. - Add the
/status,/sectors,/marketentries toFAMILIESinserver/reactPageRoutes.ts, and the three menu paths toreactPageForRoute(). - Write the components and
*Types.ts, register the kinds intypes.ts,components.client.ts,components.server.ts, add CSS and its@importinclient/src/index.css(pattern:new-react-page; themes:theme-system). - Run
deploy-gate, thenui-before-after(desktop and mobile), thenship-to-production.