page-company
The per-company pages on sahin.io/angel-investments — the company profile (/{company}) and its investors page (/{company}/angel-investors). Use when building, rebuilding or changing either page, its React view, its static body, titles, descriptions or schema.
- Source file
.claude/skills/page-company/SKILL.md- Routes covered
kind:companykind:companyInvestors
Company pages
Routes
| URL | Route kind | Count today | Render path |
|---|---|---|---|
| https://sahin.io/angel-investments/{company} (e.g. https://sahin.io/angel-investments/anthropic) | company |
234 | static body + React companyView on top |
| https://sahin.io/angel-investments/{company}/angel-investors (e.g. https://sahin.io/angel-investments/anthropic/angel-investors) | companyInvestors |
215 | static body + React companyInvestorsView on top |
- Paths:
companyPath(slug)andcompanyInvestorsPath(slug)(shared/publicUrls.ts;investorRoutePathinserver/publicPortfolio.ts). createSeoRouteManifest()loopssortByMarketCap(portfolio.companies): onecompanyroute each; acompanyInvestorsroute only whenverifiedInvestorRecord(research, slug)exists.- Static body:
renderRouteDocument()→renderPublicCompanyPage/renderPublicInvestorCompanyPage(server/seoRouteManifest.ts). - React view:
reactPageForRoute()(server/publicReactPages.ts) maps kindcompany→companyView,companyInvestors→companyInvestorsView.server/publicReactDocument.tslists both inEMBED_SERVER_BODY_KINDS, so the static body is kept below the React page (embeddedServerBodystrips the company body's duplicate logo/name/one-liner block).
Files
- Static renderers:
renderPublicCompanyPage,renderPublicInvestorCompanyPage, helpersrenderCategoryCrossLinks,renderSubcategoryCrossLinks,renderPortfolioRing(ringNeighbours),renderRelatedPublicPages,renderInvestorList,eligibleCollectionsFor,investorSiblings,companyBreadcrumbs—server/seoRouteManifest.ts. - Titles/descriptions:
companyPageTitle,companyPageHeading,companyInvestorsPageTitle,companyPageDescription,companyInvestorsPageDescription(server/companyPageCopy.ts). - Props builders:
server/publicPages/companyView.ts(buildCompanyViewProps),server/publicPages/companyInvestorsView.ts(buildCompanyInvestorsViewProps). - Components/types:
client/src/publicPages/CompanyViewPage.tsx+companyViewTypes.ts,CompanyInvestorsViewPage.tsx+companyInvestorsViewTypes.ts; registered inclient/src/publicPages/types.ts,components.client.ts,components.server.ts. - CSS:
client/src/publicPages/styles/companyView.css,companyInvestorsView.css(imported fromclient/src/index.css); static body uses.company-page__*and.investor*rules inPUBLIC_PAGE_CSS(server/publicChrome.ts). - Copy:
content/pages/company-page.yaml(companyCopy()),content/pages/investor-directories.yaml(investorCopy()),content/pages/company-view.yaml,content/pages/company-investors.yaml; short names indata/company-display-names.yaml. - Data:
client/public/portfolio-data.json,data/public-investor-research.json,data/public-company-valuations.json(sourced company value viaserver/publicCompanyValue.ts),client/public/enriched-company-data.json(loadEnrichedRecords: public funding history, team, founders),client/public/company-locations.json,client/public/vc-data.json(firm links).
Sections on the page
/{company} — React companyView: header "{Company}: funding and company profile" (or "company profile" without public funding history), market/location/team line, Key Investors chips (verified research only, linking to firm pages), Funding Timeline table (when public history exists), Why I Invested, Other {Market} Investments. Then static body: badges (market, Category, Sub-Category) → facts cards (market, status, sourced company value with citation link) → "record" block with website link and link to /{company}/angel-investors → Category cross-links → Sub-Category cross-links → portfolio ring (neighbour companies) → related public pages → back-to-portfolio footer.
/{company}/angel-investors — React companyInvestorsView: "Who Invested in {Company}?" header, stat cards, angel and institutional investor cards, owner profile card, "Why Angel Investors Matter". Then static body: taxonomy badges + note → the cited investor list (renderInvestorList; sources only as /sources/{id} references) → browse panel (eligible Category/Sub-Category investor directories, /angel-investors, sibling companies in the same Category) → related pages → back link.
SEO
- Title:
companyPageTitle(name, hasFundingRounds)/companyInvestorsPageTitle(name, investorCount), fitted toPAGE_TITLE_MAX(60) byfitPageTitle. - Description:
companyPageDescription/companyInvestorsPageDescription(owner's name left out of quoted names). - Canonical:
canonicalFor(path). JSON-LD viabuildPageGraph(server/publicSchema.ts): company →ProfilePagewithmainEntityOrganization (organizationId, website assameAs, logo); investors page →WebPage+ItemListof investors + Organization with name and logo only (never a website/source URL). Breadcrumbs: hub → Category (→ Sub-Category) → company (→ "Angel investors"). - All indexable; listed in the sitemap and llms files (
server/llmsText.ts). Seeseo-head-and-schema.
Rules
- Never show the owner's private deal data on either page —
private-data-boundary.companyView.tskeeps a private-wording guard and runsfindRestrictedTermson text. - A company value appears only when
data/public-company-valuations.jsonhas a sourced figure, always with its citation. - Investor names only from verified public research; the "who invested" question belongs to /{company}/angel-investors, never to /{company} (keyword [redacted]).
- Status words/counts via
shared/portfolioStatus.ts—portfolio-counts-single-source. Slugs and new companies —public-url-conventions. Visible words in YAML —page-content-yaml.
Tests
server/seo-route-manifest.test.ts, server/company-page-copy.test.ts, server/public-company-value.test.ts, server/public-investor-research.test.ts, server/public-schema.test.ts, server/public-routing.test.ts, server/public-urls.test.ts, server/keyword-[redacted].test.ts, server/llms-text.test.ts, server/entity-facts.test.ts, server/public-data-endpoints.test.ts, server/content-in-yaml.test.ts, server/legacy-redirects.test.ts, server/seo-watchlist.test.ts.
Rebuild from scratch
- Confirm the company exists in
client/public/portfolio-data.jsonwith a valid slug (public-url-conventions) and logo in the generated logo map. - Keep the manifest loop in
createSeoRouteManifest()(company route always; investors route only with a verified record). - Write
company-page.yaml,investor-directories.yaml,company-view.yaml,company-investors.yaml; runnode scripts/sync-site-copy-module.mjs. - Implement the title/description helpers in
server/companyPageCopy.ts, then the two static renderers and theirrenderRouteDocumentcases. - Implement
buildCompanyViewProps/buildCompanyInvestorsViewProps, the two*Page.tsxcomponents + types, register them (types.ts,components.client.ts,components.server.ts), add the CSS imports — follownew-react-page. - Add both kinds to
EMBED_SERVER_BODY_KINDSand thereactPageForRoutebranches. - Run
deploy-gate→ui-before-after(a company with and without investors, desktop + mobile) →ship-to-production.