feat(marketing): free static marketing site reusing the real landing page (#382) - #383
Merged
Merged
Conversation
…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).
…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.
5 tasks
…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.
18 tasks
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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):
apps/frontendlanding page's real visual design, reused directly rather than re-invented.This PR now reflects that current state — see "What changed" below.
Linked issue
Closes #382
Scope
What changed
A new, independent site:
apps/marketing/— not a deploy of the fullapps/frontendSPA (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/frontenditself is completely untouched.apps/marketingis also not part of the root npm workspace — its ownpackage.json/lockfile, so Vercel builds it in total isolation with Root Directory set toapps/marketing.Two behavioral differences from the real landing page, since this standalone site has no backend or accounts at all:
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.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 ownLandingPage.tsxalready shows a guest visitor an "Analyze a Repository" / "Create Account" button whose actualonClickopens 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.src/data/sampleAnalysis.ts) uses the real product's actual Engineering Review category ids/labels (cross-checked againstapps/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.api/waitlist.ts, a Vercel serverless function appending to a private GitHub Gist) and aWaitlistModal/useWaitlistFormreached from "Analyze a Repository." All of it has been removed — file, tests, hook, modal, README setup instructions, and the now-unusedtsxdevDependency/test script that only existed to test that function. See the flag below re: the real backend's own/waitlistroute, 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
/waitlistfeatureThe owner asked me to check whether the real backend's
/waitlistroute andwaitlist_entriestable (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 outsideapps/marketingand this issue's scope.What I found: it's more deeply integrated than a standalone feature.
apps/backend/app/api/routes/waitlist.py'sPOST /waitlistwrites toWaitlistEntryrows (migration0012_waitlist_entries.py), whichscripts/list_waitlist.pylets the owner review before runningscripts/approve_email.py— that script's own--noteflag 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 intoapps/frontend/src/features/waitlist/(WaitlistModal,useWaitlistForm, API client), reached fromLandingPage.tsx's own guest "Analyze a Repository"/"Create Account" CTA, and its copy is echoed in bothRegisterPage's andOAuthCompletePage'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.apps/marketing/README.md— I cannot create the Vercel account/project myself.Testing performed
Manual, in-browser (not assumed from code), against the real Vite dev server, in both light and dark mode:
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
render.yaml, or any live database.Dependencies and blocked work
None for this PR. See the flagged backend
/waitlistquestion 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
devupstream/devupstream/devapps/marketing/README.md)apps/marketing/)Closes) is used only because the issue is fully resolved/waitlistquestion is flagged above, not acted on)