fix(content): lead with the trial, brand the 404 page #136

Sammanfogat
supernaut sammanfogade 5 incheckningar från feat/launch-polish in i main 2026-08-01 14:23:48 +00:00
Ägare

Launch-day copy and page fixes. Closes #133, closes #134.

#133 — pricing and sign-up never mentioned the trial

/pricing advertised 150 kr/month with paid accounts "efter sommaren 2026" and never used the word
trial, so the page the announcement drives traffic to showed a price nobody can act on while the
free-until-at-least-31-August offer sat behind an unticked box on another page.

Both locales now lead with what a visitor gets today, keep the prices as what an account becomes,
and link /trial-terms. The date framing is reused verbatim from the existing news post and control
panel rather than reworded, so there is still one phrasing site-wide. The sign-up intro follows the
existing trialOpen() kill switch, so neither the trial state nor the post-launch state carries false
copy.

The trial checkbox is deliberately left unchecked. Ticking it accepts a separate legal document, so
it is a consent control, and a pre-ticked consent box is not consent (GDPR Recital 32). It would also be
inconsistent with the Terms box directly beneath it. The conversion loss the issue identified is
answered in the copy instead. Reasoning is recorded in a comment next to the input.

Also on /pricing — the same defect in two more places

  • The organisation tier (99 kr/seat) and the add-ons read as purchasable. They are not, and
    organisations are not in the trial either — /trial-terms §1 already says so. Availability notes
    added, worded verbatim from that page. Prices kept: forward-looking price information is legitimate.
  • Swedish said "dedikerad runner" while every other Swedish surface says körare (the guides, three
    Actions FAQ entries, the contact page). Fixed, and the glossary row added to docs/content-style.md
    so it does not drift back. English keeps "runner", which is correct.
  • Two further style-guide violations on the same page: wiki, mm → wiki med mera, dvs → det vill säga.

#134 — 404 page was Astro's unbranded default

New 404.astro and its /en/ twin on the normal layout, with header, footer, language switcher and a
named navigation region pointing at documentation, news and contact. Sets the status explicitly and
Cache-Control: no-store.

The issue's suspicion about the [slug] routes was correct, and it was worse than the default.
new Response(null, { status: 404 }) sends a null body, so an unknown guide or news slug rendered
nothing at all. All four routes now Astro.rewrite() to the branded page in the right language.

Verified

pnpm format, pnpm lint (eslint + stylelint), pnpm check (0 errors, 0 warnings), pnpm mdlint,
pnpm test (149 passed) and pnpm build all pass. Checked against a running standalone server, not
just the build: /404, /en/404, unmatched paths and unknown /docs/ and /news/ slugs all return
404 with the branded page in the correct language; /404 is absent from the sitemap; the trial checkbox
markup carries no checked.

Note

#121, #122, #123 and #124 turned out to be already shipped by 8439fa4 (PR #125) — its close keywords
never fired. They have been verified against the live site and closed separately; no code here.

Launch-day copy and page fixes. Closes #133, closes #134. ## #133 — pricing and sign-up never mentioned the trial `/pricing` advertised 150 kr/month with paid accounts "efter sommaren 2026" and never used the word trial, so the page the announcement drives traffic to showed a price nobody can act on while the free-until-at-least-31-August offer sat behind an unticked box on another page. Both locales now lead with what a visitor gets **today**, keep the prices as what an account *becomes*, and link `/trial-terms`. The date framing is reused verbatim from the existing news post and control panel rather than reworded, so there is still one phrasing site-wide. The sign-up intro follows the existing `trialOpen()` kill switch, so neither the trial state nor the post-launch state carries false copy. **The trial checkbox is deliberately left unchecked.** Ticking it accepts a separate legal document, so it is a consent control, and a pre-ticked consent box is not consent (GDPR Recital 32). It would also be inconsistent with the Terms box directly beneath it. The conversion loss the issue identified is answered in the copy instead. Reasoning is recorded in a comment next to the input. ## Also on /pricing — the same defect in two more places - The organisation tier (99 kr/seat) and the add-ons read as purchasable. They are not, and organisations are not in the trial either — `/trial-terms` §1 already says so. Availability notes added, worded verbatim from that page. Prices kept: forward-looking price information is legitimate. - Swedish said "dedikerad **runner**" while every other Swedish surface says **körare** (the guides, three Actions FAQ entries, the contact page). Fixed, and the glossary row added to `docs/content-style.md` so it does not drift back. English keeps "runner", which is correct. - Two further style-guide violations on the same page: `wiki, mm` → `wiki med mera`, `dvs` → `det vill säga`. ## #134 — 404 page was Astro's unbranded default New `404.astro` and its `/en/` twin on the normal layout, with header, footer, language switcher and a named navigation region pointing at documentation, news and contact. Sets the status explicitly and `Cache-Control: no-store`. **The issue's suspicion about the `[slug]` routes was correct, and it was worse than the default.** `new Response(null, { status: 404 })` sends a *null body*, so an unknown guide or news slug rendered nothing at all. All four routes now `Astro.rewrite()` to the branded page in the right language. ## Verified `pnpm format`, `pnpm lint` (eslint + stylelint), `pnpm check` (0 errors, 0 warnings), `pnpm mdlint`, `pnpm test` (149 passed) and `pnpm build` all pass. Checked against a running standalone server, not just the build: `/404`, `/en/404`, unmatched paths and unknown `/docs/` and `/news/` slugs all return 404 with the branded page in the correct language; `/404` is absent from the sitemap; the trial checkbox markup carries no `checked`. ## Note #121, #122, #123 and #124 turned out to be already shipped by 8439fa4 (PR #125) — its close keywords never fired. They have been verified against the live site and closed separately; no code here.
supernaut lade till 4 incheckningar 2026-08-01 14:18:04 +00:00
The announcement drives traffic to /pricing, which advertised 150 kr a month and
never mentioned the trial that is the offer actually on the table. /signup had the
mirror problem: it described the account you get as a participant account and put
hosting your own repositories behind "the paid account", which cannot be bought
yet.

- /pricing now opens with the trial, links the trial terms, and frames the prices
  as what an account will cost, with a short note beside the price list.
- pricing.description leads with the trial, since that is the line a search result
  shows.
- The sign-up intro follows the trial kill switch: while the trial is open it
  leads with what a visitor gets today; the previous wording stays for the world
  where paid subscriptions exist.
- The date framing is reused verbatim from the trial terms, the news post and the
  control panel ("at least until 31 August 2026" / "minst till 31 augusti 2026").

The trial checkbox stays unchecked. Ticking it accepts a separate legal document,
so it is a consent control and a pre-ticked consent box is not consent; it would
also not match the Terms box beneath it. The conversion loss is answered in the
copy instead.
There was no src/pages/404.astro, so a mistyped or dead URL served Astro's
framework default: unbranded, no navigation, no language switch, English only
whatever the locale. It is the page most likely to be seen by someone following a
broken external link.

Adds 404.astro and its /en/ twin on the normal Base layout, with the site header,
footer and language switcher, plus a named navigation region linking the home,
documentation, news and contact pages. Strings live in ui.ts like any other page.

The [slug] routes were worse: `new Response(null, { status: 404 })` is a 404 with
an empty body, so a wrong guide or news URL rendered nothing at all, not even the
framework default. All four now rewrite to the branded page in their own locale,
which leaves the URL as typed. The page sets its own 404 status, since a rewrite
from a route that did match carries the matched route's status, and sets
Cache-Control: no-store so a mistyped URL is never cached as content.

Verified against the built standalone server: /404, /en/404, an unmatched path in
both locales, and unknown /docs/ and /news/ slugs in both locales all return 404
with the branded page in the right language; /404 is absent from the sitemap.
Two follow-ups on /pricing, the page the announcement drives traffic to.

Availability. The organisation tier had the same defect the personal tier did: 99
kr a month read as a purchasable product, when organisations can be neither bought
nor created today and are explicitly not part of the trial. The add-ons table read
the same way. Both now carry an availability line, worded verbatim from
/trial-terms so the page and the terms cannot drift ("Att skapa organisationer
ingår inte i provperioden…" / "Creating organisations is not part of the trial…").
The prices stay: they are legitimate forward-looking information, they just must
not read as available now.

Terminology. The Swedish page called it a "runner". Every other Swedish surface
says "körare" — the Actions guide, three FAQ answers and the contact page, nine
uses in all — so the pricing page was the straggler, not the convention. Added the
term to the content-style glossary so the next writer does not re-invent it. Also
spelled out two Swedish shorthands the guide requires in full ("mm", "dvs"); the
English twin keeps "runner", which is correct there.
fix(signup): tell people where their username is written down
Alla kontroller lyckades
ci / ci (pull_request) Successful in 1m16s
9d694a9081
Partial for #127. The resend form asks for the one thing a user who never received
their set-up email may not remember, and the field said only "Your username".

It now also says where that username is written down (the set-up email greets the
user by it), and why an email address cannot stand in for it: the new link only
ever goes to the address already on the account, so an address the caller types is
never a destination. The `pattern` on the input already rejects an address before
submission, so the previous behaviour was a rejected field with no explanation.

The lookup itself is NOT implemented. Resolving an address to an account needs
either a Kanidm attribute search — which has to be confirmed against the live
server with the portal's own scoped token before anything is built on it — or a
stored keyed digest of the address, which costs a migration, a new secret, and
still helps no account created before the column exists. Storing derived personal
data to work around a lookup that may already exist is the wrong order of
operations, so that decision is left open rather than pre-empted here.
supernaut lade till 1 incheckning 2026-08-01 14:20:57 +00:00
fix(content): the homepage pricing teaser led with cost, not the trial
Alla kontroller lyckades
ci / ci (pull_request) Successful in 1m7s
4eb4648226
The homepage is the page a public announcement is most likely to link, and its
only pricing signal was 'see what a Gitborg account costs'. Same defect as on
/pricing: the visitor is pointed at a price they cannot act on rather than at
the offer that is actually live. Both locales now say it costs nothing during
the trial first, then keep the existing link.
supernaut sammanfogade incheckning 9b25680aa3 till main 2026-08-01 14:23:48 +00:00
supernaut tog bort grenen feat/launch-polish 2026-08-01 14:23:49 +00:00
Logga in för att delta i denna konversation.
Inga granskare
Ingen milstolpe
Inget projekt
Inga tilldelade
1 deltagare
Notiser
Förfallodatum
Förfallodatumet är ogiltigt eller utanför gränserna. Använd formatet "åååå-mm-dd".

Inget förfallodatum satt.

Beroenden

Inga beroenden satta

Referens
bitborg/bitborg-web!136
Ingen beskrivning angiven.