This commit is contained in:
Felix Klement committed 2026-10-05 21:04:51 +02:00
1 parent efecc500c4
commit cd45c5d98f
24 files changed
+689 -281

No files matched your search

+16 -10
View File
@@ -44,7 +44,7 @@ Environment; see *Contact form* below.
| `src/components/verifier/*` | The CipherVerifier product page, in page order: Hero (line burst), Intro (image band), HowItWorks (five group cards, one schematic each; on wide screens the heading is sticky and the cards stack under it as you scroll), Cards, Facts, Outro. |
| `src/components/verifier/SoonHero.astro`, `ComingSoon.astro` | The coming-soon version of `/cipherverifier`, shown while `verifierComingSoon` in `src/data/flags.ts` is true: hero on a build-time SVG relief of ridge lines in the logo blues, under the floating header, "Coming soon." with the alpha sign-up beside it, a status strip, and the product name set across the full width and cut by the hero's lower edge, release path, spec sheet and the first schematic. Copy in `ui.verifier.soon`. |
| `src/components/verifier/diagrams.ts` | The five schematics as data: a hand-placed wide layout and an auto-generated tall spine per group. `Schematic.astro` renders either. Labels come from `ui.verifier.how.groups`; the tuple shape is in `types.ts`. Every element carries the `group` of the node it belongs to, which drives the hover focus and the draw-in order. |
| `server/contact.mjs` | The contact form handler: validates, rate-limits and sends by SMTP. Its own `package.json`, so the image only carries nodemailer. |
| `server/contact.mjs`, `server/mail/` | The handler for both forms (contact, alpha sign-up): validates, checks the proof of work, rate-limits and sends by SMTP. `server/mail/confirm.mjs` lays out the confirmation email (tables, inline styles, logo as an inline attachment). Its own `package.json`, so the image only carries nodemailer and altcha-lib. |
| `scripts/*.mjs` | Review tooling: `shot.mjs` (full page), `scroll-shots.mjs` (viewport by viewport), `tabs-test.mjs` (keyboard test for the sectors tabs), `contact-sheet.mjs`. Need `npx astro preview --port 4322`. |
| `src/pages/_*.astro` | Shared page bodies. `index.astro` and `de/index.astro` render `_Home.astro` with a `lang` prop, and so on. |
| `src/assets/images/` | Source images. Astro emits AVIF with a WebP fallback and explicit dimensions. |
@@ -59,7 +59,7 @@ Environment; see *Contact form* below.
## Things the host has to provide
- **Contact form.** The form posts `first_name`, `last_name`, `email`, `message`, `lang` and a
honeypot field `website` to `POST /contact`. That one path is handled by `server/contact.mjs`
honeypot field `website` to `POST /contact`. That path is handled by `server/contact.mjs`
(Node, nodemailer), which sends the message by SMTP to `CONTACT_TO` with the sender as
Reply-To. The form sends in place and shows the result in a toast; a post that asks for HTML
is redirected to `/contact/sent` or `/contact/error` (under `/de` for German). Both pages are
@@ -74,7 +74,7 @@ Environment; see *Contact form* below.
and no third party is involved, so there is nothing to consent to. The form therefore needs
JavaScript; without it a `<noscript>` line points to the email address.
In the container, nginx proxies `/contact` and `/contact/challenge` to the handler on `127.0.0.1:3000`; both are started
In the container, nginx proxies `/contact`, `/contact/challenge`, `/notify` and `/notify/verify` to the handler on `127.0.0.1:3000`; both are started
by `docker/entrypoint.sh`, which restarts the handler if it crashes. If the handler is down,
visitors are sent to the error page. Without SMTP settings the handler does not start and the
rest of the site is served as usual.
@@ -88,18 +88,24 @@ Environment; see *Contact form* below.
| `CONTACT_TO` | `office@ciphercell.de` | Where messages go. |
| `SMTP_SECURE` | by port | Force TLS from the start (`true`) or not (`false`). |
| `SMTP_REQUIRE_TLS` | `true` | `false` only for a local mail catcher. |
| `NOTIFY_SECRET` | random per start | Signs alpha confirmation links (`openssl rand -hex 32`). Set it, or links sent before a restart stop working. |
| `SITE_URL` | `https://www.ciphercell.de` | Base of the confirmation links. |
| `ALTCHA_HMAC_SECRET`, `ALTCHA_HMAC_KEY_SECRET` | random per start | Signing secrets for the challenge (`openssl rand -hex 32`). Set them so a restart does not void challenges already handed out. |
In Dokploy, set these under the application's Environment. Locally, put them in `.env` (see
`.env.example`), run `npm run contact` next to `npm run dev`; the dev server proxies `/contact` and
`/contact/challenge` to it.
`.env.example`), run `npm run contact` next to `npm run dev`; the dev server proxies the same paths to it.
- **Alpha sign-up.** While `verifierComingSoon` in `src/data/flags.ts` is true, `/cipherverifier`
shows a coming-soon page whose form posts `email`, `consent=yes`, `lang`,
`list=cipherverifier-alpha` and the honeypot `website` to `POST /notify`. The handler is
server-side and not part of this static build. It should store the address with the time of
consent, confirm it by double opt-in, and redirect back with a thank-you. The privacy page
promises deletion after the alpha mail is sent. Set the flag to false to bring back the full
product page.
`list=cipherverifier-alpha`, the honeypot `website` and the proof-of-work answer `altcha` to
`POST /notify`, handled by `server/contact.mjs` like the contact form. It is double opt-in
without a database: the handler emails the address a link to `/notify/confirm` carrying a
signed token (address, language, time of consent; valid 7 days) and keeps nothing. That page
posts the token to `POST /notify/verify` with a button (mail scanners open links, they do not
press buttons), and the handler sends the confirmed registration, with the consent wording and
both times, to `CONTACT_TO`. That mailbox is the list. The privacy page promises deletion
after the alpha mail is sent or on withdrawal. The result pages `/notify/confirmed` and
`/notify/error` are `noindex` and left out of the sitemap. Set the flag to false to bring back
the full product page.
- **Matomo.** The privacy page links to the existing opt-out on `cipher.uber.space`. The tracking
snippet itself is not included; add it in `src/layouts/Base.astro` if analytics should continue.