Skip to content

last.vet-web

Public site and marketing pages for LastVet (Last 1 Enterprises). Next.js static export deployed to Cloudflare Pages (out/). API backend runs on AWS (ECS + RDS, us-west-2) behind api.last.vet, not this repo.

Develop

npm install
npm run dev

Open http://localhost:3000.

Investor decks

All decks are React slide pages (1280×720) in components/deck/, exported to PDF via node scripts/export-decks-pdf.mjs. Raise exports two PDFs by default; pass --no-notes to skip the internal (speaker-notes) version. Deployed as static HTML on Cloudflare Pages.

Route PDF Password Notes
/deck LastVetCaseDeck.pdf No Single narrative deck. First send. Unlisted (noindex).
/opportunity LastVet-Opportunity-Deck.pdf No Partner invitation. Unlisted only.
/raise LastVet-Raise-Deck.pdf No Full fundraise deck, 22 slides only — safe to send. Unlisted only.
/raise LastVet-Raise-Deck-internal.pdf No Same deck, 44 pages (22 slides interleaved with speaker notes) — internal only.
/raise/expansion, /expansion LastVet-Expansion-Deck.pdf Yes Gate 1 — default passphrase tell me more
/raise/trajectory LastVet-Trajectory-Deck.pdf Yes Gate 2 — default passphrase show me the machine

Password gates are client-side courtesy locks (sessionStorage + SHA-256 hash at build time). Only expansion and trajectory require a passphrase.

Case deck copy source: export Google Doc to docs/case-deck/. Product screenshots: public/deck/case/*.png (~420×720 @2x).

Field brief (proof-of-problem one-pager)

Public outreach asset at /brief (indexed, no password gate). React page in components/brief/ with the navy/olive/rust dossier design and cited CCN stats.

Send-ready PDF: decks/export/LastVet-Field-Brief-v*.pdf. Bump the version suffix when stats or copy change (CCN figures are dated and will need refreshing).

npm run export:field-brief

Uses Playwright print at letter size with backgrounds (scripts/export-field-brief-pdf.mjs). Not part of the slide deck export pipeline.

Build

npm run build

Produces static output in out/ for Cloudflare Pages.

Mandatory for any legal change. Do not edit changelog or policy files without following:

docs/legal/LEGAL_RELEASE.md

npm run legal:release   # validate + sync JSON to ../last.vet-api

GitHub secrets for my.last.vet deploy: scripts/sync-github-cloudflare-secrets.sh (from Bitwarden SM).

Deploy (Cloudflare Pages)

Project: last-vet-web (Git integration). Settings in wrangler.toml:

Setting Value
Build command npm run build
Build output out

my.last.vet is deployed by GitHub Actions (.github/workflows/deploy-my-last-vet.yml) on every push to main, so it stays aligned with last.vet.

my.last.vet (veteran landing)

Separate Pages project: last-vet-my. Settings in wrangler.my.toml:

Setting Value
Build command npm run build:my
Build output out
Custom domain my.last.vet

CLI deploy (after wrangler login or CLOUDFLARE_API_TOKEN set):

npm run cf:deploy:my

Then attach my.last.vet under Workers & Pages → last-vet-my → Custom domains. The homepage veteran door links to https://my.last.vet; do not deploy the splitter until this domain resolves.

Optional local preview: npm run dev:my (port 3002) or last.vet/veteran on the marketing build.

Optional Cloudflare env vars (only if passphrases change from defaults):

Variable Purpose
NEXT_PUBLIC_RAISE_EXPANSION_PASSWORD_HASH SHA-256 hex of normalized gate-1 passphrase
NEXT_PUBLIC_RAISE_TRAJECTORY_PASSWORD_HASH SHA-256 hex of normalized gate-2 passphrase

Gates are client-side courtesy locks on a static site (sessionStorage + hash compare at build time). No Vercel or Node server required for this app.

Legal copy source files: LASTVET_PRIVACY_POLICY.md, LASTVET_TERMS_OF_SERVICE.md (rendered at /privacy and /terms).