Skip to main content

Milestone 15: Marketing site

Purpose: Marketing and legal pages live; contact form stores submissions and sends email; SEO and analytics in place.

Exit state: Landing, pricing, contact (with DB + Postmark); legal pages (terms, privacy, impressum); sitemap, metadata, Plausible optional; blog stub.

Spec reference: §2.13 Marketing Website, §3.13 Internationalisation (i18n), §5.21b ContactSubmission, §6.1 Marketing routes, §9.12 Marketing env.

Prerequisites: M14. ContactSubmission table in M01; Postmark in M08.


15.1 Landing and pricing

Tasks

  1. Landing page

    • Route /. Section 2.13: Hero (headline, subhead, CTA "Start free trial", "See pricing"); Problem/Solution; Key features (3–4); How it works (3 steps); Pricing teaser; Social proof placeholder; Final CTA; Footer (Pricing, Contact, Legal, theme toggle). Static or SSG. Section 6.1. All copy via next-intl from messages/en/marketing.json (Section 3.13, 2.13).
  2. Pricing page

    • Route /pricing. Section 2.13: Plan comparison (Starter, Growth, Business, Enterprise); inboxes, features per plan; monthly/annual toggle; CTA per plan ("Start free trial" → /signup; Enterprise → /contact). FAQ section. Pricing content from config (TypeScript or JSON) for plan data; all user-facing labels and copy via next-intl (messages/en/marketing.json). Section 6.10, 3.13.
  3. Rendering

    • Marketing route group (marketing); force static where possible (export const dynamic = 'force-static'). Section 2.13. Uses same next-intl setup as app (Section 2.13 table).

Acceptance criteria

CriterionStatus
Landing and pricing render; CTAs link to /signup and /contact; no auth required.Pending
Pricing content manageable (config file); annual/monthly toggle if applicable.Pending
Marketing copy (landing, pricing, contact) uses next-intl; strings in messages/en/marketing.json per Section 3.13.Pending

15.2 Contact form

Tasks

  1. Form

    • Route /contact. Fields: name, email, company (optional), subject (dropdown: General, Sales, Support, Partnership), message. Section 2.13. Validation: client (react-hook-form + Zod) and server (Route Handler or tRPC). Honeypot + rate limit (e.g. 3 per IP per hour). Section 2.13.
  2. Submit

    • Insert contact_submissions row (id, name, email, company, subject, message, ip_address hashed/truncated, created_at). Section 5.21b. Send email to CONTACT_EMAIL via Postmark (template or simple text). Success: inline confirmation; no redirect. Section 2.13.
  3. Env

    • CONTACT_EMAIL required; document in Section 9.12.

Acceptance criteria

CriterionStatus
Form validates and submits; row in DB; email received at CONTACT_EMAIL.Pending
Rate limit and honeypot prevent abuse; success message shown.Pending
No enumeration (same message for success).Pending

Tasks

  1. Routes

    • /legal/terms (AGB), /legal/privacy (Datenschutz), /legal/impressum (Imprint). Section 2.13. Content from MDX in content/legal/ (or similar). Shared LegalLayout: typography, ToC for long pages, last-updated. Section 2.13.
  2. Content

    • Placeholder or lawyer-reviewed copy; mark [LEGAL REVIEW REQUIRED] if placeholder. For DE/AT/CH: Impressum and Datenschutz in German; use next-intl with default locale or locale-based routes so /legal/impressum can serve German content (Section 2.13). Document chosen approach (single locale vs locale-based legal pages).
  3. 404

    • Custom not-found page with link back to home; Section 2.13.

Acceptance criteria

CriterionStatus
Legal routes render; content editable via MDX; layout consistent.Pending
404 page exists and is linked from marketing.Pending

15.4 SEO and analytics

Tasks

  1. Metadata

    • generateMetadata per page (title, description); OpenGraph where applicable. Section 2.13.
  2. Sitemap

    • /sitemap.xml auto-generated (Next.js or custom); include /, /pricing, /contact, /legal/*. Section 2.13.
  3. robots.txt

    • Allow all except /app/** and /api/** (or appropriate). Section 2.13.
  4. Plausible

    • Optional: NEXT_PUBLIC_PLAUSIBLE_DOMAIN; inject script in marketing layout only; no cookie banner for strict necessity. Section 2.13, 9.12.

Acceptance criteria

CriterionStatus
Metadata and sitemap present; robots.txt disallows app and API.Pending
Plausible loads when env set; no cookie banner (or document if needed).Pending

15.5 Blog stub

Tasks

  1. Route
    • /blog: "Coming soon" or placeholder. Section 2.13. Structure in place for future articles.

Acceptance criteria

CriterionStatus
/blog returns 200 with coming soon content.Pending
Ready for M16 (Polish and observability).Pending

Milestone 15 sign-off

CriterionStatus
All tasks in 15.1–15.5 complete.Pending
All acceptance criteria met.Pending
Marketing site and contact form production-ready; legal and SEO in place.Pending
E2E: Landing, pricing, contact form, legal pages (see INDEX — Testing strategy).Pending
Ready for M16 (Polish and observability).Pending