# MailHub Public Landing Page Design ## Goal Replace the current “anonymous root URL → login/admin app” experience with a **developer-first public marketing homepage** (Resend / Mailjet-inspired). Unauthenticated visitors see product value, API/SMTP/Webhook integration paths, and bilingual CTAs; authenticated users still reach the admin console at `/`. ## Product Decisions | Item | Choice | |------|--------| | Audience | Developers first | | Scope (MVP) | Single-page landing with in-page anchors | | Language | zh-CN / en-US toggle (localStorage) | | Pricing | None | | Implementation | Static landing entry (Vite `landing` build), decoupled from React admin bundle | | Visual system | Same Modern SaaS indigo tokens as admin (`#4F46E5`, canvas, ink) | ## Non-Goals (MVP) - Multi-page docs site, blog, changelog site - Pricing tables or billing - Embedding the landing page inside the React admin SPA - Changing send/webhook business APIs - Fake customer logos or fabricated social proof ## Current Behavior (to change) - Unauthenticated browser traffic to protected pages redirects to `/login`. - `/` maps to `public/index.html` (admin app). - Login/register assets are public; admin is session-gated. ## Routing & Auth | Path | Unauthenticated | Authenticated | |------|-----------------|---------------| | `GET /` | Serve **landing** (`landing.html`) | Serve **admin** (`index.html`) | | `/login`, `/register`, `/forgot-password`, `/resend-verification`, `/reset-password` | `login.html` | Optional redirect to admin if already logged in (existing) | | `/app` (optional alias) | Redirect to `/login` | Admin console | ### Server rules (`src/server.js`) 1. Treat landing HTML/CSS/JS as **login-class public assets** (no session required), same pattern as `/login.html`. 2. For `GET /` (or mapped `/index` root): - If `getRequestUser` is present → `index.html` (admin). - Else → `landing.html`. 3. Do **not** redirect anonymous `/` to `/login`. 4. Keep `/api/*` auth unchanged. 5. **Caching:** Root HTML responses that depend on session (`GET /` landing vs admin) MUST be non-cacheable: e.g. `Cache-Control: private, no-store` (and prefer the same for `landing.html` / `index.html` HTML documents) so proxies/browsers do not stick a visitor on the wrong shell after login. 6. **`/app` alias:** out of MVP; primary CTAs use `/register` and `/login` only. ## Information Architecture (single page) ### Sticky header - Brand: MH mark + MailHub - Anchor nav: Features · Integrate · API · SMTP · Webhooks - Language toggle: 中文 / EN - CTAs: Log in (secondary), Sign up / Get started (primary) ### Hero - Developer-oriented headline + subcopy (self-hosted, DKIM/SPF/DMARC, logs, webhooks) - Primary CTA → `/register` - Secondary CTA → `#api` (scroll) - Visual: dark code panel with curl `POST /api/send` sample ### Trust strip (light) - Text chips only: Self-hosted · DKIM · SPF · DMARC · Delivery webhooks - No fake logos ### Features grid (5–6 cards) 1. Domain + DNS automation 2. SMTP Submission 3. HTTP Send API + tokens 4. Delivery tracking & logs 5. Webhooks (`sent` / `bounced` / `failed`) 6. Multi-user isolation ### Integrate (3 columns) | Column | Content | |--------|---------| | API | Token auth, `POST /api/send`, field list, link to register | | SMTP | Host/ports aligned with product submission config, example snippet | | Webhooks | Event types + signature headers summary, “configure after login” | ### Deep sections - **#api** — curl + JSON body + Authorization header (match existing token docs field names) - **#smtp** — ports and connection notes consistent with runtime submission - **#webhooks** — event type table + `X-MailHub-Signature` one-liner ### Closing CTA - Headline + Register + Log in - No pricing ### Footer - Product name, Log in, Register, optional GitHub link - Copyright line ## Static sample content policy Landing is **fully static** (no authenticated API on first paint). - Use **placeholders** for host/base URL: `https://mail.example.com`, host `mail.example.com` (or “your MailHub host” in prose). - Document **default public SMTP ports** from product defaults: `25` (smtp), `587` (smtp/STARTTLS), `465` (smtps), `2525` (smtp). Do not hardcode a specific production hostname from env. - **Forbidden in MVP:** unauthenticated config API for landing; build-time injection of production `.env` into landing assets. - API sample fields match product helpers: `from`, `to`, `subject`, `text`; header `Authorization: Bearer `. - Webhook samples: events `sent` | `bounced` | `failed`; payload `type` `email.sent` / `email.bounced` / `email.failed`; header `X-MailHub-Signature: t=…,v1=…`. ## Visual Design - CSS variables aligned with admin redesign: - `--mh-primary: #4F46E5` - canvas / ink / border / radius / shadow - Light marketing layout; dark code blocks for developer feel - Comfortable spacing; responsive stack; mobile nav collapse or wrap - System font stack (no CDN Inter required) ## Internationalization - Dictionary module for `zh-CN` and `en-US` - Persist choice in `localStorage` (key e.g. `mailhub-landing-locale`) - Default: `navigator.language` starts with `zh` → zh-CN, else en-US - Toggle updates all `data-i18n` nodes and `document.documentElement.lang` - Code identifiers remain English; comments/labels in dictionary may switch ## Engineering ### Build (committed path) **Vite multi-page entry only** (same pipeline as `index` / `login`): - Source: repo-root `landing.html` + `src/frontend/landing/main.ts` + `landing.css` + i18n dictionary - `vite.config.ts` input key: `landing` - Output: `public/landing.html` + hashed assets under `public/assets/` Do not maintain a parallel hand-written-only `public/landing.html` source of truth outside the Vite build. ### Client behavior - Smooth scroll for header anchors - Copy-to-clipboard on code samples - No API calls required for first paint ### Tests - Server: anonymous `GET /` body/title or content-type indicates landing (or path resolution helper unit test) - Server: authenticated session `GET /` resolves to admin index - Public: landing assets reachable without cookie - Optional: i18n dictionary has both locales for required keys ## File Map (expected) | Path | Role | |------|------| | `landing.html` (source) | Landing markup | | `src/frontend/landing/main.ts` | i18n, interactions | | `src/frontend/landing/landing.css` | Styles | | `src/frontend/landing/i18n.js` | Copy dictionary | | `vite.config.ts` | `landing` input | | `src/server.js` | Root routing + public asset allowlist | | `test/server-*.test.js` | Route tests | | `public/landing.html` + assets | Build output | ## Delivery Order 1. Landing static structure + CSS tokens + zh/en copy 2. Landing JS (i18n, scroll, copy) 3. Vite entry + build 4. Server public routing for `/` and assets 5. Tests + build gate 6. Deploy per Agents.md ## Success Criteria - Anonymous `/` shows marketing landing, not login form as the only chrome - Bilingual toggle works and persists - Register/Login CTAs work - Logged-in `/` still loads admin console - Existing auth and API behavior unchanged - `npm test` and `npm run build` pass ## Open Follow-ups - Full `/docs` site - Pricing page - Marketing analytics - Open Graph / social meta images