ADR-016: The landing page is a separate, lightweight site with scripted quality checks
Who is this for
Section titled “Who is this for”Front-end developers — read this before adding a dependency, a client component or a new kind of animation.
- Separate repository and hosting: the landing page shares no code, database or bot process with the product. The only link is the leads endpoint and its shared secret.
- Next.js App Router with Server Components by default; all motion is CSS, WAAPI and View Transitions.
- No UI kits, no animation library, no 3D, no generated assets at build time.
- Structure, palette, motion and layout rules are enforced by scripts, not by review alone.
- Status: accepted.
Context
Section titled “Context”The page has one job: explain the product in a few seconds and collect a request. Its audience opens it on phones, often from a messenger. The team also wanted the page to demonstrate the product without calling it — every demo on the page is a mock-up drawn in code, so the page never costs money to show.
It is the second landing page of the product line; the first one set the structure and the quality bar.
Decision
Section titled “Decision”- Isolation. Nothing is imported from the product repository. Sticker images are copied as finished files; no product tool is ever run from the landing repository.
- Rendering. Sections are Server Components. Client components exist only where interaction requires them, and each receives only its slice of the dictionary.
- Performance rules learned from measurement: the first screen does not wait for JavaScript; mock-ups below the fold mount when approached; the validation library is loaded on submit; only the needed image widths are generated; fonts never block the first frame.
- Motion. Only
transformandopacityare animated, with a short documented list of exceptions; anything that loops is paused off-screen and in hidden tabs; reduced-motion users get the final state. - Secrets. The form is a server action. The leads secret and the bot token are server-only variables and never carry the public prefix; a test checks it.
- Locales. Russian, Uzbek and English under
/ru,/uz,/en. Uzbek is published but never chosen automatically. - Verification.
audit,shots,film,lighthouse,contrastandjs-weightscripts run against a local server; each has a watchdog that fails after a minute without progress.
Alternatives considered
Section titled “Alternatives considered”| Alternative | Why not |
|---|---|
| A page inside the product’s FastAPI app | Couples marketing releases to event-critical deploys. |
| A component kit or animation library | Weight on the first screen and a generic look; the measured cost of one validation library alone was a 106 KB chunk. |
| Real product calls for the demo | Costs money per visitor and can fail in front of a client. |
Consequences
Section titled “Consequences”- The form’s validation rules exist twice — in the landing schema and in the server’s validator — and must be changed together. Tests on both sides use the same examples.
- Mobile LCP is currently limited by first-screen JavaScript (about 172 KB gzip, 3.5–3.6 s in Lighthouse’s simulation); the accepted level is a performance score above 90 — see Known gaps.
- The repository’s notes still list an animation library in the stack, but it is not a dependency.
Evidence
Section titled “Evidence”CLAUDE.mdof the landing repository, sections “Stack”, “No paid calls”, “Motion” and amendment 8.package.json;src/lib/deliverRequest.test.ts.
Where to go next
Section titled “Where to go next”Last verified: 2026-11-13 against ai-sticker-pack@b715418 and ai-stickers-landing@e350ff5.