This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Static website for OpSight Intelligence (opsightintel.com), hosted on GitHub Pages with Cloudflare DNS. Four business verticals:
- Fraud Intelligence (
/fraud,/ko/fraud,/tr/fraud—src/pages/*/fraud.astro, copy insrc/i18n/fraud.ts; migrated 2026-09-15): Telegram intelligence for financial institutions, regulators and compliance teams — collect / connect / warn / deliver, coverage by market, live dated numbers, no public pricing (on request), no client reference.public/intelligence.htmlis now a redirect stub to/fraud(canonical + meta refresh +noindex, follow); do not delete it, links to it are in the world. - Manufacturing Intelligence — lens names are Opsight's own: throughput, cycle-time efficiency, utilisation, ROI. Never "run rate" or "capacity" (product names on the operator's employer's roadmap, 2026-09-16), and never a real company name in demo data (the supplier demo once named eight real Korean firms; all replaced by Greek-letter placeholders). (
/manufacturing,/ko/manufacturing—src/pages/*/manufacturing.astro, copy insrc/i18n/manufacturing.ts; migrated 2026-09-15; the unsourced "$2 billion" hero line dropped, everything else word for word, the worked insights and demos labelled Synthetic): forensic operational insights for Tier 1 manufacturers, positioned explicitly against dashboards — each finding carries root cause, quantified dollar impact, ranked actions, a causal-vs-correlational judgment, and success criteria. Excel-native input, no IT project, cross-industry rather than auto-only. - Procurement Intelligence (
/procurement,/ko/procurement—src/pages/*/procurement.astro, copy insrc/i18n/procurement.ts; migrated 2026-09-15; the maritime "in development" roadmap and the vessel/Copernicus disclaimer were dropped from the page, and the call to action is the aggregate sample, not a named-firm record, until the licence and naming questions are answered): Korean public procurement — every tender, bidder and winning price against the published estimate (기초금액), collected nightly from 조달청 / 나라장터 open APIs. Renamed frommaritime.htmlon 2026-08-10 — the old name shipped a fishing-industry word and an anchor icon on a Korean public-tender product, which is what a recipient saw first when the link was shared.maritime.htmlremains as a redirect stub (canonical + meta refresh +noindex, follow) because links to it are already out in the world; do not delete it. GitHub Pages cannot issue a real 301, so the stub is the honest substitute. The SAR/AIS shipbuilding thesis this page used to carry is not sellable (detector precision 0.57, 2 of 11 yards SAR-legible, AIS receiving nothing) and was removed on 2026-08-07 — seeopsight-company/strategy/gtm/SELLABILITY_MAP.md§3 before putting it back. Sub-brand is OPSIGHT PROCUREMENT;drydockremains the internal package name only and must not appear in customer-facing copy. - OpSentry (
/opsentry—src/pages/opsentry.astro, copy insrc/i18n/opsentry.ts; migrated 2026-09-15,/ko/opsentryadded the same day; the anonymous testimonial became the plain fact it described, the two value-less tiles got their numbers, plan buttons lead to the repo or a mail): AI coding assistant security guardrails. Three-layer enforcement, 203 tests, ISO 27001/EU AI Act/Korean AI Basic Act compliance. Free + Team ($15/dev/mo) + Business ($25/dev/mo) tiers.
- Astro (static output) from v0.10.0, built by GitHub Actions
(
.github/workflows/pages.yml) and published to GitHub Pages from the build artifact.npm run buildwritesdist/; nothing indist/is committed. - Migration is page by page.
src/pages/holds the migrated pages (today: every page inen/ko; fraud also intr). Still served verbatim frompublic/: themaritime.htmlandintelligence.htmlredirect stubs anddemodashboard/. On GitHub Pages a<name>.htmlfile wins over a<name>/index.htmldirectory, which is how the page-by-page migration worked.public/index-legacy.htmlis the pre-Astro home page, kept until the new one has been read in both languages, then deleted. - The design layer is
public/design/:tokens.css(brand, line accents, severity/status, surfaces, type, space — light and dark) andcomponents.css(nav, hero, stat tile, product card, badges, citation chip, callout, evidence table, form, footer; from v0.15.0 also the full-bleedband/hero-band, thelifecycleSVG styles,section--tint, hover lift and the count-up state).public/design/index.htmlrenders all of it at/design/with a theme toggle (noindex, unlisted). The Astro layout links these files rather than bundling them, so every page and/design/read the same bytes. Other repos COPY the two files (never link at runtime) and carry the same version string. - Live numbers never need a build.
stats.json,procurement-stats.jsonprocurement-figures.json(the aggregate shapes the procurement page charts, viaProcurementCharts.astro) andagent-demo.json(the manufacturing agent's last synthetic run, viaAgentDemo.astro) sit at the repo root and are rewritten nightly byopsight-fraud/scripts/deploy_website_stats.py(pushed todevelopandmain). Pages fetch them from the repo's raw URL (raw.githubusercontent.com/opsight-intelligence/opsight-website/main/…), and the Pages workflow ignores those paths, so a stats push costs no Actions minutes and the figures still move every night. A tile whose file cannot be read keeps its dash — nothing stale or invented is shown. - Copy lives in
src/i18n/<page>.ts, one object per locale, with the shared nav/footer/live labels insrc/i18n/common.ts; each page is one component (src/components/<Page>.astro) insidesrc/layouts/Base.astro(head, hreflang for every locale the page has, nav with a language switch, footer). English at/…, Korean at/ko/…, Turkish at/tr/…where a page has it (fraud).HeroBand.astro(navy band +Lifecycle.astroSVG, or the per-line figureArtFraud/ArtProcurement/ArtManufacturingvia theartslot — invented shapes, never data) opens every page;LiveStats.astrois the one runtime fetch for stat tiles and counts the numbers up. Korean written by the agent needs a native read before the professional launch — correct it in the copy object. public/og/<page>.pngare the Open Graph images, generated bynode scripts/og.mjsfrom an SVG card on the tokens — rerun after a title change and commit the PNGs.public/demodashboard/keeps the generated Plotly dashboards, restyled onto the tokens bydashboard.cssplus a nav and a Synthetic line injected into each file (noindex).src/config.tsholds public site configuration:FORMSPREE_ID(the contact form's Formspree id; empty = compose-a-mail fallback). Change it there, bump, release — no env, no secret.CNAME,favicon.svg,robots.txtlive inpublic/and ship unchanged.public/sitemap.xmlis generated byscripts/sitemap.mjsbefore every build (one URL persrc/pages/**/*.astro, lastmod from git) and is not tracked.scripts/check-dist.mjsruns after every build and fails it when an internal link is broken or an indexed page lacks a title, description or canonical;.github/workflows/checks.ymlruns the build on every PR.website.mdis the Cloudflare/SEO checklist; not published.
npm ci # once; Node 22+
npm run dev # http://localhost:4321, live reload
npm run build # writes dist/ — what Pages serves
npm run preview # serve dist/ locally
npm run build is the check: it generates the sitemap, builds, and runs
check-dist (links, title, description, canonical on every indexed page).
Then look at the two home pages in both themes.
The migrated pages are bilingual by construction: / (English) and /ko/
(Korean) come from the same component and copy object, with hreflang
alternates in the head and a language switch in the nav.
The fraud page additionally has Turkish (/tr/fraud), because its buyers
include Turkish firms.
Branching, versioning, changelog, and documentation rules are in CONTRIBUTING.md. In short:
- Work on
feature/*offdevelop; never commit tomainordevelopdirectly mainis what GitHub Pages serves — a push tomainthat touches source triggers the Pages build; stats-only pushes do not (seepages.yml)- Every commit bumps
VERSION, adds aCHANGELOG.mdentry, and updates affected docs - New pages are
src/pages/<name>.astro+src/pages/ko/<name>.astrowith a copy object insrc/i18n/, given a nav entry inBase.astro, and described in the Project Overview above (the sitemap picks them up on its own) - Routine
stats.jsonrefreshes still take a PATCH bump, but are grouped in the changelog rather than listed one per refresh mainanddevelopare guarded by a client-sidepre-pushhook that is not version-controlled — see README.md for the installer to run in a fresh clone