# Cameleer marketing website — design spec

**Date**: 2026-04-24
**Status**: Approved for implementation planning
**Project**: `cameleer-website`
**Target domains**: `www.cameleer.io` (marketing), redirects from apex `cameleer.io`

---

## 1. Overview

Build the public marketing website for Cameleer — a zero-code observability platform for Apache Camel applications. The site lives at `www.cameleer.io`, serves as the top-of-funnel for the SaaS product at `platform.cameleer.io`, and routes all authentication (sign-up, sign-in, password reset) to Logto at `auth.cameleer.io`.

The SaaS backend (`cameleer-saas` repo) and per-tenant observability servers are built and operated separately; this project ships the marketing surface only.

---

## 2. Goals

1. Communicate Cameleer's value proposition to two audiences in parallel — integration managers and engineers — within a single homepage scroll.
2. Convert visitors into Logto sign-ups via a prominent "Start free trial" path.
3. Ship a 100% static site with **no server-side code**, no sessions, no database, no form handlers — the smallest possible attack surface that still does the job.
4. Fit the existing Cameleer ecosystem — Mission Control design tokens, Gitea-hosted repo, Gitea Actions CI, Hetzner hosting, Cloudflare security layer.
5. Be production-ready for DACH-enterprise buyers: DSGVO-compliant, TMG §5 imprint, TLS-only, WAF-protected.

---

## 3. Non-goals

Explicitly **out of scope** for this project:

- Blog, docs, features page, about page, changelog, case studies
- Contact forms, newsletter signup, lead-capture, email automation
- Interactive product demos, video players
- Analytics, tracking pixels, cookie consent banners
- Multi-language content (English only; i18n-ready scaffolding only)
- Custom sign-up or sign-in forms (all auth redirects to Logto)
- CMS integration, image CDN, headless commerce
- Per-PR preview deployments (single Hetzner document root)
- Any backend code on the marketing host

These can be added later without rewriting the foundation. Astro content collections will be scaffolded so a blog or docs section is a content task, not a refactor.

---

## 4. Audience (first-class constraint)

Two primary audiences visit the homepage, often on the same buying cycle:

| Audience | Role | What they need from the page |
|----------|------|------------------------------|
| **Managers** (amber in mockups) | Integration leads, architects who sign the check | Business outcomes, risk reduction, proof-by-pedigree, pricing clarity |
| **Engineers** (cyan in mockups) | Camel developers, DevOps, SREs | Capability, mechanism, coverage, zero-code mechanics |

**Drafting rule**: every section on the homepage is labelled during writing with its primary audience lean. No section is allowed to drift into generic "dashboard SaaS" voice. Sections that serve both audiences pair an outcome (manager) with a capability (engineer) within the same block.

---

## 5. Architecture

### 5.1 Stack

- **Framework**: Astro 5 (static output, `output: 'static'`).
- **Styling**: Tailwind CSS via `@astrojs/tailwind`.
- **Design tokens**: Mission Control palette duplicated into `tailwind.config.mjs` — dark `#060a13`, amber `#f0b429`, cyan `#5cc8ff`, rose for errors, green for success, neutral grays.
- **Typography**: DM Sans (UI) and JetBrains Mono (data/code). Self-hosted WOFF2 in `public/fonts/` with `font-display: swap` — **no Google Fonts network call** (both faster and GDPR-clean).
- **No React** in v1. If a future interactive island is needed (pricing calculator, animated demo), it can be added via `@astrojs/react` without touching the rest of the site.
- **Content collections**: `src/content/en/` per-locale layout from day one. `de/` is a future-only scaffold — not populated in v1.

### 5.2 Deployment target

- **Host**: Hetzner Webhosting L (shared hosting: SFTP/SSH, Apache with `.htaccess`, Let's Encrypt origin cert).
- **Document root**: `public_html/www.cameleer.io/` (subject to Hetzner account layout).
- **No PHP, MySQL, or cron** used. Shared hosting is used strictly as a static file host.

### 5.3 Security posture

The design target is **"nothing to exploit"**: no executable code on the origin, no writable endpoints, nothing that accepts user input. Every layer below is defense-in-depth against that baseline.

**Cloudflare layer** (all zones on `cameleer.io` proxied — orange cloud):

- SSL/TLS mode: **Full (strict)**. Cloudflare validates the Hetzner Let's Encrypt cert.
- Minimum TLS version: **1.2**. TLS 1.3 enabled.
- Always Use HTTPS: on.
- Automatic HTTPS Rewrites: on.
- HSTS: `max-age=31536000; includeSubDomains; preload` — site added to the HSTS preload list once stable.
- WAF: Cloudflare Managed Ruleset enabled (OWASP-aligned, free-plan-eligible).
- Bot Fight Mode: on.
- Rate limiting: 20 requests / minute per IP on `/*`.
- Browser Integrity Check: on.
- Security level: medium.
- Email Obfuscation: on.

**Origin-IP hygiene**: all DNS records for `cameleer.io` are proxied. No bare `A`, `AAAA`, or `MX` records leaking the Hetzner origin IP. Email (if needed at the apex) uses Cloudflare Email Routing or a separate provider at an unrelated hostname.

**Edge security headers** (Cloudflare Transform Rules + an Astro response middleware for defense in depth):

| Header | Value |
|--------|-------|
| `Content-Security-Policy` | Strict, scoped — `default-src 'self'; img-src 'self' data:; style-src 'self' 'unsafe-inline'; font-src 'self'; script-src 'self'; connect-src 'self'; frame-ancestors 'none'; base-uri 'self'; form-action 'none'; object-src 'none'`. Sign-in/sign-up buttons are plain `<a>` navigations to `auth.cameleer.io` — no `fetch`, no `<form>` submits — so `connect-src` and `form-action` stay maximally strict. |
| `X-Frame-Options` | `DENY` |
| `X-Content-Type-Options` | `nosniff` |
| `Referrer-Policy` | `strict-origin-when-cross-origin` |
| `Permissions-Policy` | `geolocation=(), microphone=(), camera=(), payment=()` |
| `Strict-Transport-Security` | (handled by Cloudflare HSTS setting) |

`'unsafe-inline'` is retained for `style-src` to accommodate Astro's critical-CSS inlining; it can be hardened to nonce-based in a future pass if desired. `script-src` is strict — no inline scripts, no CDN scripts.

**Apache-level** (via `.htaccess` in document root):
- Force HTTPS (redundant with Cloudflare but defense in depth).
- Disable directory indexing.
- Block hidden-file access (`.git`, `.env`, etc.) — should never exist on the origin but double-locked.
- Gzip/Brotli compression for text assets.
- Cache-Control: `public, max-age=31536000, immutable` for `/assets/*` (hashed filenames); `public, max-age=3600, must-revalidate` for HTML.

### 5.4 Authentication flow

The marketing site **owns no auth state** and **stores no credentials**.

1. User clicks "Start free trial" or "Sign in" on any page of `www.cameleer.io`.
2. Browser navigates to `https://auth.cameleer.io/oidc/auth?...` (Logto's hosted sign-in UI — already customized in `cameleer-saas/ui/sign-in/`).
3. Logto handles sign-up / sign-in / password reset / MFA / social providers.
4. On success, Logto redirects to `https://platform.cameleer.io/...` — the SaaS app.

"Start free trial" and "Sign in" may differ only by the `first_screen` query parameter (`first_screen=register` vs `first_screen=sign-in`). The exact query-string contract is owned by the `cameleer-saas` project and is documented there, not here — the website treats the auth URL as an opaque string from config.

**Configuration**: the two auth URLs are environment-configurable in Astro (`ASTRO_AUTH_SIGNIN_URL`, `ASTRO_AUTH_SIGNUP_URL`) so the sign-in conventions can evolve on the SaaS side without a website code change.

---

## 6. Information architecture

### 6.1 Pages (Tier S)

Four pages, all static, all English:

1. `/` — Home
2. `/pricing` — Pricing
3. `/imprint` — Imprint (TMG §5)
4. `/privacy` — Privacy Policy (DSGVO)

Plus root-level redirects:
- `cameleer.io` → `www.cameleer.io` (Cloudflare Page Rule — permanent redirect).

### 6.2 Homepage structure (6 sections, dual-register weave)

Every section is tagged with its primary audience lean:

1. **Hero** (both) — Route-topology diagram as the primary visual. Overlaid: eyebrow ("Observability · Apache Camel"), headline (outcome statement that reads equally well to managers and engineers), one-line subhead, CTA pair.
2. **Dual value-prop tiles** (both) — 3 tiles. Each tile pairs an **outcome line** (manager-facing) with a **capability line** (engineer-facing). Example shape: *"Cut debugging time in half"* (outcome) + *"Processor-level tracing with payload capture, no code changes"* (capability).
3. **How it works** (engineer) — 3 numbered steps: (1) Add the `-javaagent` flag, (2) Launch your app, (3) See every route, processor, and exchange. Code snippet showing the flag.
4. **Why us — moat + nJAMS pedigree** (manager) — Two halves: (a) the Cameleer moat (zero-code ByteBuddy agent + route-graph extraction + bidirectional protocol — what no one else has), (b) the team — the people who built nJAMS, now focused on Camel specifically.
5. **Pricing teaser** (manager) — 4 tier cards with headline price/benefit, link to `/pricing` for detail.
6. **CTA pair** — "Start free trial" (engineer-friendly, self-serve) + "Talk to sales" (manager-friendly, `mailto:`).

### 6.3 Pricing page

4 tiers as either a card row (desktop) stacking on mobile, or a feature-comparison table — choose during implementation based on visual density.

| Tier | Price | Environments | Apps | Retention | CTA |
|------|-------|--------------|------|-----------|-----|
| **Trial** | Free, 14 days | 1 | 2 | 1 day | Start free trial → Logto `first_screen=register` |
| **MID** | **20 € / month** | 2 | 10 | 7 days | Start → Logto `first_screen=register` |
| **HIGH** | Contact sales | Unlimited | 50 | 90 days | Contact sales → `mailto:` |
| **BUSINESS** | Contact sales | Unlimited | Unlimited | 365 days | Contact sales → `mailto:` |

A short feature-delta list under each tier card (from `cameleer-saas/HOWTO.md`): Trial = Topology; MID = + Lineage, Correlation; HIGH = + Debugger, Replay; BUSINESS = All features.

> **Cross-repo alignment note**: `cameleer-saas/HOWTO.md` (as of 2026-03-27) specifies `MID = 30 days retention`. This spec publishes **7 days**. Before go-live, either the SaaS backend tier config or the website copy must be updated to match. Tracked in §10.

### 6.4 Imprint (`/imprint`)

DSGVO + TMG §5 compliant. Required content (to be supplied by user during implementation):

- Legal name of operating entity (natural person or company)
- Full postal address
- Contact email and optionally phone
- VAT ID (Umsatzsteuer-ID per §27a UStG) if applicable
- Commercial register entry if applicable (Handelsregister number + court)
- Responsible party per §55 Abs. 2 RStV if the site publishes editorial content (may not apply here)
- Disclaimer block and link-liability boilerplate

English-language text is permitted — DSGVO and TMG do not mandate German.

### 6.5 Privacy Policy (`/privacy`)

Because v1 has **no analytics, no cookies, no forms, no third-party scripts**, the privacy policy is unusually short. It documents:

- Server access logs on Hetzner (IP, timestamp, user-agent) — standard log retention (Hetzner default), legal basis Art. 6(1)(f) GDPR.
- Cloudflare acting as a processor (standard DPA, data centers, traffic inspection for security).
- Cookies: **none set by this site**. Explicit statement.
- External link behavior (links to `auth.cameleer.io` and `platform.cameleer.io` — subject to those services' separate policies).
- Data subject rights (access, rectification, erasure, complaint to DPA).
- Controller contact (same as imprint).

If Plausible or any analytics is added later, this page will need a new section — flagged in §10.

---

## 7. Visual design

### 7.1 Tokens (Mission Control)

| Token | Value | Usage |
|-------|-------|-------|
| `--bg` | `#060a13` | Page background |
| `--bg-elevated` | `#0c111a` | Cards, panels |
| `--border` | `#1e2535` | Dividers, card borders |
| `--border-strong` | `#2a3242` | Stronger dividers, button outlines |
| `--accent` | `#f0b429` | Amber — primary accent, CTAs |
| `--cyan` | `#5cc8ff` | Cross-route links, secondary accent |
| `--rose` | tbd on implementation | Errors (not used in marketing v1) |
| `--green` | tbd on implementation | Success (not used in marketing v1) |
| `--text` | `#e8eaed` | Primary text |
| `--text-muted` | `#9aa3b2` | Secondary text |
| `--text-faint` | `#6b7280` | Tertiary / timing metadata |

Font families: `"DM Sans", system-ui, sans-serif` for UI; `"JetBrains Mono", ui-monospace, SFMono-Regular, monospace` for code and data.

### 7.2 Signature visual

A **subtle topographic contour pattern** as a full-page background layer (~10–18% opacity) — the "mapping routes" metaphor referenced in product branding. Implemented as an inline SVG or a tiled SVG `background-image`; no raster asset.

### 7.3 Hero diagram

The homepage hero foregrounds a stylized **Camel route-topology graph** — nodes for endpoints and processors, edges with a highlighted "cross-route" dashed cyan line. Rendered as inline SVG (crisp, scalable, selectable), **not** a screenshot. This is Cameleer's unique artifact and the hero's job is to show it in the first paint.

---

## 8. Build and deploy

### 8.1 Repository

- **Name**: `cameleer-website`
- **Host**: `gitea.siegeln.net/cameleer/cameleer-website`
- **Default branch**: `main`
- **`.gitattributes`**: `* text=auto eol=lf` (cross-platform line-ending consistency).
- **`.gitignore`**: `node_modules/`, `dist/`, `.astro/`, `.env*`, `.superpowers/`, editor directories.

### 8.2 Local development

```bash
npm ci
npm run dev    # Astro dev server on http://localhost:4321
npm run build  # Produces dist/
npm run preview
```

### 8.3 CI/CD — Gitea Actions

`.gitea/workflows/deploy.yml` — triggered on push to `main`:

1. Checkout.
2. Setup Node 20 LTS.
3. `npm ci`.
4. `npm run build`.
5. Validate: HTML5 conformance check (`html-validate` or similar), broken-link check against internal links (`linkinator`).
6. Deploy via `rsync -avz --delete dist/ $SFTP_USER@$SFTP_HOST:$SFTP_PATH/` over SSH using ed25519 key stored as Gitea Actions secret. The `--delete` flag keeps the document root clean of orphaned files from earlier builds.

**Secrets** (stored in Gitea Actions):
- `SFTP_HOST` — Hetzner Webhosting L SSH hostname
- `SFTP_USER` — hosting user
- `SFTP_PATH` — absolute path to document root
- `SFTP_KEY` — ed25519 private key (PEM format)
- `SFTP_KNOWN_HOSTS` — Hetzner SSH host key fingerprint (pinned, protects against MITM on deploy)

**Host-key pinning is mandatory** — deploy MUST fail if the remote fingerprint doesn't match. No `StrictHostKeyChecking=no`, no `UserKnownHostsFile=/dev/null`.

### 8.4 Rollback

Rollback is `git revert <commit> && git push` on `main`. The CI pipeline re-runs and republishes the prior state. There is no separate artifact store — the `main` tip is always authoritative.

---

## 9. Operational prerequisites (user-owned, outside this project)

These must be true before the first deploy succeeds:

1. Hetzner Webhosting L provisioned, SSH access enabled, ed25519 public key added to `~/.ssh/authorized_keys`, document root for `www.cameleer.io` created.
2. `cameleer.io` domain active on Cloudflare; nameservers at registrar pointed to Cloudflare.
3. DNS records (all proxied — orange cloud): `www` → Hetzner origin; apex (`@`) → Hetzner origin; `auth` → SaaS cluster; `platform` → SaaS cluster.
4. Hetzner origin cert provisioned via Let's Encrypt (or Hetzner's auto-SSL for the document root).
5. Cloudflare settings per §5.3 configured (WAF, rate limit, security headers via Transform Rules, HSTS, bot protection).
6. Gitea Actions secrets populated per §8.3.

A one-page "operator checklist" will be produced as part of implementation to walk these in order.

---

## 10. Cross-repo alignment / follow-up items

These are **not blockers** for the website build but need resolution before public go-live:

| Item | Owner | Resolution path |
|------|-------|-----------------|
| MID-tier retention: spec says 7 days, `cameleer-saas/HOWTO.md` says 30 | Hendrik | Either patch SaaS tier config or update website copy |
| Exact Logto URL query-string contract (`first_screen` support, post-login redirect target) | `cameleer-saas` | Document in SaaS side; website reads from env |
| Imprint content (legal name, address, VAT ID, contact) | Hendrik | Supplied during implementation |
| nJAMS legacy claim (on the "Why us" section) — any wording needed to avoid trademark issues with the current owner of nJAMS | Hendrik | Review before go-live |
| Plausible analytics: whether to add in v1.1 | Hendrik (later) | Separate follow-up — needs a one-line script tag + privacy policy update |

---

## 11. Testing and acceptance

**Automated (in CI)**:

- Astro build succeeds without warnings.
- HTML validator passes on all emitted pages.
- Internal link checker reports zero broken links.
- Lighthouse CI thresholds on the homepage: Performance ≥ 95, Accessibility ≥ 95, Best Practices ≥ 95, SEO ≥ 95.
- Security-header check: `curl -I` against the deployed URL returns the full §5.3 header set.

**Manual acceptance (per-section approval during implementation)**:

- Every homepage section reviewed with its audience label; copy approved by Hendrik before merge.
- Pricing table reviewed against active SaaS tier config.
- Imprint reviewed against current DACH legal requirements.
- Privacy policy reviewed against actual data flows (logs, Cloudflare).

**Post-deploy smoke checks**:

- `www.cameleer.io` returns 200 with the HSTS header.
- Apex `cameleer.io` → `www.cameleer.io` redirect works.
- "Start free trial" link points to the configured Logto URL.
- No origin IP visible via `curl` or via a naked subdomain.
- Mobile Safari, Chrome, Firefox render the homepage hero correctly.

---

## 12. Future-but-scaffolded

The project is laid out so these extensions are **content tasks, not refactors**:

- `src/content/en/` and `src/content/de/` directory structure from day one. Adding `/de/*` becomes a pure content / AI-translation task.
- `src/content/blog/` and `src/content/docs/` directories stubbed with a README — no live routing yet but a future phase can wire them up without restructuring.
- Plausible analytics ready to drop in (one `<script>` tag plus a privacy-policy section).
- React island capability (`@astrojs/react` installable, no integration code needed until the first island exists).

---

## 13. Decisions recorded

| # | Decision | Alternative considered | Rationale |
|---|----------|------------------------|-----------|
| 1 | Astro 5, static output | Next.js SSG, plain HTML, Hugo | Noted in `cameleer-saas/CLAUDE.md`; zero-JS default matches security goal; content collections fit the i18n plan |
| 2 | Redirect to Logto for auth (no local forms) | Lead-capture form, embedded iframe | Eliminates backend code on marketing host; leverages the already-customized Logto sign-in UI |
| 3 | Hetzner Webhosting L + Cloudflare proxy | Cloudflare Pages, Vercel | User-specified host; static files on shared hosting behind WAF is the "boring, hard-to-break" profile |
| 4 | Tailwind + Mission Control tokens (no React) | Pull `@cameleer/design-system` React components | Marketing components share nothing with SaaS dashboard components; zero-JS wins on speed and attack surface |
| 5 | No analytics, no cookie banner (v1) | Plausible from day one, Google Analytics + banner | Respects "unhackable" ethos; banner-free page; Plausible is a 5-minute add later |
| 6 | English only, i18n-ready | DE + EN now, EN only and retrofit later | Ships fastest without boxing out DACH later; AI-translation when ready |
| 7 | Dual-register homepage flow (6 sections) | Engineer-forward, manager-forward | Dual-audience constraint requires both audiences served at every scroll depth |
| 8 | Diagram-hero (route topology as hero visual) | Type-first hero, split-with-console hero | Leads with Cameleer's unique artifact (the route graph) — matches moat identified in `STRATEGY.md` |
| 9 | Gitea Actions → rsync-over-SSH to Hetzner | Manual SFTP, Cloudflare Pages | Every deploy is a git commit; rollback is `git revert`; fits existing Gitea Actions skill base |
| 10 | ed25519 SSH key for deploy | RSA 4096 | Matches existing Ed25519 key convention in `cameleer-saas` |
| 11 | `auth.cameleer.io` for Logto | `id.cameleer.io`, `login.cameleer.io`, path under `platform` | Matches Logto's own conventions; keeps auth infra visibly separate |

---

## 14. Risks and mitigations

| Risk | Mitigation |
|------|------------|
| Origin IP leak via unproxied DNS record | DNS audit in prerequisites checklist; all records proxied; no mail at apex |
| Hetzner SFTP credentials compromised | Ed25519 key only, no password auth, host-key pinning in deploy workflow, keys rotatable without code change |
| CSP too strict — breaks Astro's inline styles | Spec allows `'unsafe-inline'` for styles (Astro critical-CSS); scripts remain strict |
| Pricing-tier drift between site and SaaS config | Listed as cross-repo alignment item §10; resolve before go-live |
| nJAMS legacy claim legal risk | Flagged for Hendrik's review before public go-live |
| Logto sign-in URL contract changes | Auth URLs read from env, not hard-coded — one config change, no rebuild |
| Shared-hosting outage / degraded origin | Cloudflare's Always Online / caching serves stale-while-offline for HTML |
