Skip to content

feat(marketing): free static marketing site reusing the real landing page (#382) - #383

Merged
parthrohit22 merged 4 commits into
devfrom
feature/382-marketing-site-vercel
Sep 1, 2026
Merged

feat(marketing): free static marketing site reusing the real landing page (#382)#383
parthrohit22 merged 4 commits into
devfrom
feature/382-marketing-site-vercel

Conversation

@parthrohit22

@parthrohit22 parthrohit22 commented Sep 1, 2026

Copy link
Copy Markdown
Collaborator

Summary

Product pivot (owner): pause the real Render/Neon backend deployment (no funding right now, revisit later — #375/#377 left exactly as merged/paused, untouched by this PR). Build a free, static marketing/awareness launch instead: the real product's own landing page, repurposed as a static site with a scripted product simulation using realistic canned data and a "run it yourself" CTA to the repository — none of it needing a live backend.

Redesign notes (this PR evolved through two reworks after the initial build, both visible in earlier commits):

  1. Replaced the original hand-built Hero/SimulationDemo/RunItYourself composition with the actual apps/frontend landing page's real visual design, reused directly rather than re-invented.
  2. Removed the waitlist entirely, per a product-direction clarification from the owner: PARTHA stays self-hostable only for the foreseeable future, with no hosted service planned — there's nothing to put anyone on a waitlist for. "See how it works" was also changed to open the demo simulation directly (same as "Log In" already did) instead of scrolling to an anchor section.

This PR now reflects that current state — see "What changed" below.

Linked issue

Closes #382

Scope

  • Issue or RFC this advances: feat(marketing): free static marketing site with a scripted product simulation #382.
  • Why this is in scope: an explicit product-direction decision from the owner — a parallel, zero-cost track while the real backend stays paused.
  • Accepted evidence it is real: production build inspected and clean, the page verified in-browser in both light and dark mode (simulation run end to end on both result tabs, run-it-yourself instructions, FAQ, footer, all remapped hotspots).

What changed

A new, independent site: apps/marketing/ — not a deploy of the full apps/frontend SPA (its other routes — login, register, dashboard — all need a live backend this pivot explicitly doesn't have right now). It reuses that app's landing page specifically: the same 1728px-wide authored SVG artwork, the same light/dark/system theme system, the same brand tokens, FAQ, and footer, ported in directly (src/assets/landing/, src/hooks/useLandingTheme.ts, src/components/ThemeSwitcher.tsx, src/utils/cn.ts, src/styles/globals.css, tailwind.config.ts) rather than re-invented. apps/frontend itself is completely untouched. apps/marketing is also not part of the root npm workspace — its own package.json/lockfile, so Vercel builds it in total isolation with Root Directory set to apps/marketing.

Two behavioral differences from the real landing page, since this standalone site has no backend or accounts at all:

  • The "Log In" nav hotspot and the "See how it works" hero hotspot both open a scripted product simulation instead (src/components/DemoModal.tsx) — there's nothing live to log into and no walkthrough section to scroll to, so both lead to the same demo.
  • Every "Analyze a Repository" hotspot has no live backend to analyze against, so it opens fork/clone setup instructions instead (src/components/RunItYourselfModal.tsx), with a note encouraging visitors to star the repo. There is no waitlist or hosted-beta path anywhere on the site.

This mirrors an existing, shipped pattern in the real app itself: apps/frontend's own LandingPage.tsx already shows a guest visitor an "Analyze a Repository" / "Create Account" button whose actual onClick opens a modal rather than performing the literal labeled action, with an sr-only label clarifying the real behavior. The same softened-by-an-immediately-clarifying-modal shape is used here for the remapped hotspots.

  • The simulation's canned data (src/data/sampleAnalysis.ts) uses the real product's actual Engineering Review category ids/labels (cross-checked against apps/backend/app/review/review_service.py's _CATEGORY_LABELS) and severity levels, and the real Insights response shape (cross-checked against the generated OpenAPI types). The repository and findings are fictional; the shape and vocabulary are not invented. Labeled persistently as a scripted walkthrough of a sample repository, never implied to be a live analysis.
  • "Run it yourself" uses the exact commands from the main README's own "Run PARTHA locally" section (checked directly against it).
  • No waitlist: the original build had a waitlist form (api/waitlist.ts, a Vercel serverless function appending to a private GitHub Gist) and a WaitlistModal/useWaitlistForm reached from "Analyze a Repository." All of it has been removed — file, tests, hook, modal, README setup instructions, and the now-unused tsx devDependency/test script that only existed to test that function. See the flag below re: the real backend's own /waitlist route, which is a separate, larger question outside this PR's scope.

Removed over the course of this PR's two reworks: the five original hand-built components (Hero.tsx, Footer.tsx, SimulationDemo.tsx, RunItYourself.tsx, WaitlistForm.tsx), and later the waitlist infrastructure described above (WaitlistModal.tsx, useWaitlistForm.ts, api/waitlist.ts, api/waitlist.test.ts).

Flagged, not acted on: the real backend's own /waitlist feature

The owner asked me to check whether the real backend's /waitlist route and waitlist_entries table (pre-dating this session, issue-driven) are also dead weight now that the product direction is confirmed self-host-only with no hosted service planned — but not to touch it, since it's outside apps/marketing and this issue's scope.

What I found: it's more deeply integrated than a standalone feature. apps/backend/app/api/routes/waitlist.py's POST /waitlist writes to WaitlistEntry rows (migration 0012_waitlist_entries.py), which scripts/list_waitlist.py lets the owner review before running scripts/approve_email.py — that script's own --note flag is documented as "e.g. which waitlist entry this is for," i.e. the waitlist is the intended intake mechanism feeding the admin-managed allowlist from #374/#375. On the real frontend, it's wired into apps/frontend/src/features/waitlist/ (WaitlistModal, useWaitlistForm, API client), reached from LandingPage.tsx's own guest "Analyze a Repository"/"Create Account" CTA, and its copy is echoed in both RegisterPage's and OAuthCompletePage's rejection messaging ("This email hasn't been approved for access yet... join the waitlist and we'll be in touch"). Removing it would mean touching the backend route/model/migration/script/tests and the frontend's waitlist module, LandingPage.tsx, RegisterPage, OAuthCompletePage, and the router — a real, cross-cutting change, not a small one. Leaving as-is pending your and Parth's call.

Acceptance criteria completed

  • apps/marketing: independent static Vite/React/TS site, brand-consistent (reuses the real landing page design), zero backend dependency, builds cleanly.
  • Scripted simulation using the real category/severity vocabulary, clearly and persistently labeled as a simulation, reachable from both "Log In" and "See how it works."
  • Prominent CTA to the GitHub repo with a star-the-repo note; README's "Run PARTHA locally" instructions checked for accuracy.
  • No waitlist or hosted-beta path anywhere on the site, matching the confirmed self-host-only product direction.
  • Production build verified locally; the page verified visually in-browser in both light and dark mode.
  • Deploy instructions for Parth in apps/marketing/README.md — I cannot create the Vercel account/project myself.

Testing performed

cd apps/marketing
npm install                  → 0 vulnerabilities
npm run typecheck             → tsc -b --noEmit, clean
npm run lint                  → eslint ., clean
npm run build                  → tsc -b && vite build, clean

Manual, in-browser (not assumed from code), against the real Vite dev server, in both light and dark mode:

  • "Log In" hotspot → opens the demo modal; ran the simulation end to end, confirmed all 5 progress steps complete, both the Engineering Review and Repository Insights tabs render correctly with the real category/severity vocabulary and sample findings.
  • "See how it works" hero hotspot → opens the same demo modal (confirmed, both themes).
  • "Analyze a Repository" hotspot (all three positions share the same handler) → opens the run-it-yourself modal with the fork/clone commands and star-the-repo link; confirmed no waitlist link remains anywhere in the modal.
  • FAQ hotspots, theme switcher (System/Light/Dark), and footer controls (external links resolve to the correct GitHub/Discord URLs; "coming soon" items show the correct toast copy) all verified working.
  • Zero console errors throughout.

Screenshots

Verified visually in-browser per the session's standard, in both light and dark mode, covering the hero, demo modal (both result tabs), run-it-yourself modal, and FAQ — not attached here, but real screenshots were taken and inspected, not skipped.

Security and data considerations

  • No PARTHA account, session, or credential of any kind is involved anywhere on this site — the reused landing page's "Log In" hotspot deliberately does not lead to any login flow here.
  • No form on this site collects or transmits any visitor data — the waitlist form (and the GitHub PAT it depended on) has been removed entirely.
  • Nothing here talks to the real backend, render.yaml, or any live database.

Dependencies and blocked work

None for this PR. See the flagged backend /waitlist question above — that's the owner's and Parth's call, not a blocker for this PR.

Scope changes or remaining work

None for this PR's scope. Deploying the site (Vercel account/project creation) is explicitly Parth's own step, documented in apps/marketing/README.md.

Contributor checklist

  • This PR targets dev
  • I claimed the issue and had it assigned or acknowledged before starting substantial work
  • The branch was created from an up-to-date upstream/dev
  • The branch is rebased on the latest upstream/dev
  • This PR addresses one clearly scoped issue
  • This PR is in scope: it advances a tracked issue (Scope section filled)
  • Every acceptance criterion I claim as complete is actually complete
  • Relevant tests pass (typecheck/lint/build, per Testing performed)
  • Documentation is updated for any user-visible change (apps/marketing/README.md)
  • No secrets, credentials, local env files, or generated artifacts are included
  • No unrelated files were changed (only apps/marketing/)
  • Closing syntax (Closes) is used only because the issue is fully resolved
  • Dependencies and follow-up work are linked (none blocking — the backend /waitlist question is flagged above, not acted on)

…imulation (#382)

Pauses the real Render/Neon backend deployment (no funding right now,
revisit later -- see #375/#377, left exactly as merged/paused, untouched
here) in favor of a free, static marketing/awareness push: a scripted
product simulation, a "run it yourself" CTA, and a working waitlist form,
none of it needing a live backend.

New, independent site (apps/marketing/), not a deploy of the existing
apps/frontend SPA: that app's other routes (login, register, dashboard)
all need a live backend this pivot explicitly doesn't have right now, and
shipping dead/broken auth flows to the public would undercut the point of
a clean marketing push. apps/frontend is completely untouched. Not part of
the root npm workspace either -- its own package.json/lockfile, so Vercel
can build it in total isolation with Root Directory set to apps/marketing.

- Hero, a scripted "Run the simulation" walkthrough, a "run it yourself"
  section, and a waitlist modal -- all hand-built React/Tailwind (not a
  deploy of the image-based main LandingPage), sharing the main product's
  color tokens/logo for brand consistency without any cross-package
  dependency.
- The simulation's canned data (src/data/sampleAnalysis.ts) uses the real
  product's actual Engineering Review category ids and labels (cross-
  checked against apps/backend/app/review/review_service.py's
  _CATEGORY_LABELS) and severity levels, and the real Insights response
  shape (cross-checked against the generated OpenAPI types) -- the
  repository and findings themselves are fictional, but the shape and
  vocabulary are not invented. Labeled persistently in the UI, in the hero,
  and in the waitlist copy as a scripted demo against a sample repository,
  never implied to be a live analysis.
- "Run it yourself": the exact commands from the main README's own "Run
  PARTHA locally" section (checked against it directly, and that section
  was independently verified accurate this session -- dev:backend/
  dev:frontend scripts confirmed to exist and match).
- Waitlist: api/waitlist.ts, a Vercel serverless function, appends
  submissions to a private GitHub Gist via a fine-grained PAT -- chosen
  over a new third-party form service since it needs no new account (only
  GitHub and Vercel, both already in use) and has no realistic volume
  limit. Validated email, a honeypot field, and a clear 503 (not a crash or
  silent drop) when the required env vars aren't set yet. 6 unit tests
  (api/waitlist.test.ts, node's test runner, fetch mocked -- no real
  network/GitHub call) cover method/validation/honeypot/dedup-append/
  upstream-failure paths.
- Typed against a minimal local request/response interface instead of
  importing @vercel/node: that package's own dependency chain
  (ajv/path-to-regexp/undici via @vercel/static-config) currently carries
  real advisories, for type declarations this file didn't need more than a
  few lines of. Zero npm audit findings as a result.

Verified, not just written: npm run typecheck/lint/test/build all pass;
production build inspected (four small output files, no errors); the
actual page loaded in-browser, the simulation run end to end (all 5 steps,
both the Review and Insights tabs, all 4 sample findings with correct
severity/category rendering), and the waitlist modal opened and submitted,
confirmed via zero console errors and full-page screenshots plus
get_page_text extraction -- not assumed from the code alone.

Deploy instructions (Vercel project creation, waitlist Gist/PAT setup) are
in apps/marketing/README.md -- I cannot create the Vercel account or
project myself.
Replace the marketing site's custom-built Hero/SimulationDemo/RunItYourself
composition with the actual apps/frontend landing page as its visual basis:
the same 1728px authored artwork, light/dark/system theme system, brand
tokens, FAQ, and footer -- ported in directly rather than re-invented.

Two behavioral differences from the real app, since this standalone site
has no backend or accounts at all:

- The "Log In" nav hotspot has nothing to log in to, so it opens a scripted
  product simulation instead (DemoModal), using the same canned sample data
  as before.
- Every "Analyze a Repository" hotspot has no live backend to analyze
  against, so it opens fork/clone setup instructions instead
  (RunItYourselfModal), with a note encouraging visitors to star the repo
  and a path back to the waitlist for anyone who'd rather wait for a
  hosted beta.

Ported useLandingTheme/ThemeSwitcher/cn verbatim from apps/frontend, copied
the two landing SVG assets directly (no cross-package import, keeping this
project genuinely standalone), and rewrote globals.css/tailwind.config.ts
to match the real frontend's full token set including .landing-dark.
WaitlistModal keeps its ported visual design (literal light-mode hex
colors, tokenized dark mode) and now lives inside RunItYourselfModal as a
secondary path.

Removed the five now-superseded custom components (Hero, Footer,
SimulationDemo, RunItYourself, WaitlistForm).

Verified: typecheck/lint/test/build all clean; real in-browser
click-through in both light and dark mode covering every remapped hotspot
(Log In -> demo run-through on both result tabs, Analyze a Repository ->
run-it-yourself -> nested waitlist, FAQ, theme switcher, footer links and
notices).
@parthrohit22 parthrohit22 changed the title feat(marketing): free static marketing site with a scripted product simulation (#382) feat(marketing): free static marketing site reusing the real landing page (#382) Sep 1, 2026
…ow it works" (#382)

Product-direction clarification: PARTHA stays self-hostable only for the
foreseeable future, with no hosted service planned. There's nothing to put
anyone on a waitlist for.

- Remove WaitlistModal and its useWaitlistForm hook entirely, and every
  reference/CTA to it in RunItYourselfModal and DemoModal's own comments.
- Remove the now-dead api/waitlist.ts serverless function and its test,
  along with the WAITLIST_GITHUB_TOKEN/WAITLIST_GIST_ID setup instructions
  in the README (the whole "Waitlist form setup" section).
- Drop the now-unused tsx devDependency and the test script that ran only
  against api/waitlist.test.ts.
- RunItYourselfModal no longer needs a dark prop now that it has nothing
  left to thread it to.

Also: "See how it works" now opens the scripted demo simulation directly
(DemoModal), same as "Log in" already does, instead of scrolling to an
anchor section -- there's nothing live to log into or a walkthrough to
scroll to, so both hotspots lead to the same demo. Everything else about
the page is untouched.

Verified: typecheck/lint/build clean; real in-browser click-through in
both light and dark mode confirming "See how it works" opens the demo and
"Analyze a Repository" no longer offers a waitlist path.
…382)

Replace the centered overlay-popup pattern used by DemoModal,
RunItYourselfModal, and the FAQ dialog with a shared slide-in drawer
(SlidePanel) that animates in from the right edge over part of the
screen, instead of appearing as a popup overlapping the page.

Purely a presentation/interaction change -- every dialog's actual content
and behavior is unchanged, only the container. Along the way, added two
behaviors the old centered popups didn't have: closing on Escape and on a
backdrop click (both standard for a drawer, neither carried over from the
previous pattern since it never had them).

Each dialog keeps its own width (DemoModal wider at max-w-3xl for its
two-tab results view, RunItYourselfModal and the FAQ panel narrower) and
its existing internal scroll/sticky-header behavior, now scoped to the
panel's own scroll container instead of the old centered box's.

Verified: typecheck/lint/build clean; real in-browser click-through in
both light and dark mode confirming all three panels slide in from the
right, the sticky header inside DemoModal stays pinned while its content
scrolls, the Close button works, and a backdrop click dismisses the
panel.
parthrohit22 added a commit that referenced this pull request Sep 1, 2026
PARTHA stays self-hosted only for the foreseeable future, with no hosted
service planned -- there's no reason for a fresh guest on a self-hosted
instance to be funneled through a waitlist in the UI before they can even
try registering.

The landing page's unauthenticated "Analyze a Repository" hotspots
(nav, hero, and footer positions -- all three share the same analysisCta
handler) now link directly to /register, the same way the "Log In" nav
hotspot already links directly to /login. Removes the WaitlistModal import
and waitlistOpen state from LandingPage.tsx entirely.

Registration itself is unchanged: it still enforces the admin-managed
email allowlist (#374/#375) or the local development bypass (#384) exactly
as before. This only changes what the landing page's CTA points at, not
what completing registration requires.

Deliberately not touched, per the issue's own scope: the backend /waitlist
route, WaitlistEntry model, and the frontend's features/waitlist module
(WaitlistModal, useWaitlistForm) -- now unreferenced by the landing page
but still present and still covered by their own tests. Whether that
infrastructure should be removed entirely is a separate, larger,
cross-cutting question (flagged in PR #383, not decided yet).

Updated router.test.tsx's assertion to match the new link-based CTA
instead of the old waitlist-button one.

Verified: tsc/eslint clean, full vitest suite green (439/439, including
LandingPage.test.tsx, router.test.tsx, RegisterPage.test.tsx, and
WaitlistModal.test.tsx, which still passes since the component itself is
untouched), production build clean. Real in-browser click-through against
actual dev servers (backend + frontend) in both light and dark mode: "Log
In" opens the sign-in page, "Analyze a Repository" opens account creation,
no waitlist prompt anywhere in either path, and no "waitlist" text
anywhere on the rendered landing page.
@parthrohit22
parthrohit22 merged commit 7e52cf8 into dev Sep 1, 2026
10 of 11 checks passed
@parthrohit22
parthrohit22 deleted the feature/382-marketing-site-vercel branch September 1, 2026 20:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(marketing): free static marketing site with a scripted product simulation

1 participant