docs: record contact/draft fixes, staging URL, and DNS-01 cutover finding
CI / ci (push) Successful in 1m29s
CI / ci (push) Successful in 1m29s
Marks sections 1.3 and 1.5 fixed, adds section 2.6 for the staging URL, and records that letsencrypt-prod solves via DNS-01 against Cloudflare - which removes the HTTP-01 ordering problem from section 1.1, leaving only the question of whether bluecapstrategies.com is reachable by the cert-manager Cloudflare token. Adds section 2.5 for developer-facing copy found on the /insights/ index while fixing the draft leak. Left unfixed on purpose: what that page should say depends on the owner decision in section 1.5.
This commit is contained in:
1 parent
4e354d2721
commit
5bfc5981cd
1 file changed
+54
-18
+54
-18
@@ -26,6 +26,7 @@ Status legend: `[ ]` open · `[x]` done · `[?]` needs verification · 🛑 owne
|
||||
| `npm run seo:lint` | green, 21 pages clean |
|
||||
| `npm run test:e2e` | **42 passed / 4 failed** (stale assertions, see §2.1) |
|
||||
| CI root cause | **found + fixed in-repo 2026-09-22** — see §1.2; needs a green run to confirm |
|
||||
| Staging URL | **https://bcs.int.7tl-homelab.com** — LAN-only, valid cert (§2.6) |
|
||||
| Old WordPress site | untouched and serving — must stay that way until cutover |
|
||||
| Gitea host | KVM VM `gitea-1` (10.66.15.22), **Debian 12**, docker compose — *not* in k3s |
|
||||
| Gitea / act_runner | 1.27.3 / 3.4.2 — both healthy |
|
||||
@@ -44,10 +45,14 @@ Nothing below is optional. Cutover is unsafe until all of §1 is closed.
|
||||
- [ ] Uncomment the `tls:` block and `cert-manager.io/cluster-issuer` annotation in
|
||||
`k8s/ingress.yaml`; set `secretName: bluecap-website-tls`.
|
||||
- [ ] Use the existing `letsencrypt-prod` ClusterIssuer (present in-cluster, 472d old, Ready).
|
||||
- [ ] **Resolve the ordering problem:** HTTP-01 validation requires DNS to already point at the
|
||||
cluster, but we don't want to move DNS before a cert exists. Pick one:
|
||||
- DNS-01 issuer (preferred — issues the cert *before* cutover, zero insecure window), or
|
||||
- accept a short window: cut DNS, then let HTTP-01 solve, serving plain HTTP for ~1–2 min.
|
||||
- [x] **Ordering problem SOLVED.** `letsencrypt-prod` solves via **DNS-01 against Cloudflare**,
|
||||
not HTTP-01, so a cert can be issued *before* any DNS points at the cluster — no insecure
|
||||
window. Proven end to end on 2026-09-23: the staging host issued a valid LE cert in ~75s
|
||||
with no public reachability (§2.6).
|
||||
- [ ] 🛑 **Verify the one remaining dependency:** `bluecapstrategies.com` must be in the
|
||||
Cloudflare account that cert-manager's API token can reach. The domain is at Bluehost
|
||||
today, so this is probably **not** yet true. It is the single fact separating a clean
|
||||
zero-downtime cutover from one with a gap — check it early, not on launch day.
|
||||
- [ ] Verify `https://` serves a valid chain and HTTP→HTTPS redirects before announcing.
|
||||
|
||||
### 1.2 CI/CD is stalled — no deploy since 2026-07-20 🛑 hard blocker
|
||||
@@ -111,11 +116,13 @@ Remaining:
|
||||
uses apt at all, and the job image is no longer EOL (bookworm still serves `docker.io` fine). The
|
||||
static-binary approach remains the more durable of the two; keep it regardless.
|
||||
|
||||
### 1.3 Developer-facing copy is visible on the live contact page 🛑
|
||||
`src/pages/contact.astro:37-41` renders, to real visitors:
|
||||
> "The form is static-first and posts to the configured endpoint when
|
||||
> `PUBLIC_CONTACT_FORM_ENDPOINT` is set. Without an endpoint, it opens an email…"
|
||||
- [ ] Delete that `.form-note`. Replace with visitor-appropriate copy or nothing.
|
||||
### 1.3 Developer-facing copy on the contact page ✅ FIXED 2026-09-23
|
||||
Two notes written for developers, not visitors, were being rendered:
|
||||
- the form note explaining `PUBLIC_CONTACT_FORM_ENDPOINT`, and
|
||||
- a "Discovery note" about the WordPress page holding placeholder contact values.
|
||||
|
||||
Replaced the first with reader-facing copy and dropped the second (the deviation it described is
|
||||
already recorded in `docs/content-deviations.md`). Commit `4e354d2`.
|
||||
|
||||
### 1.4 Contact form has no endpoint 🛑
|
||||
`PUBLIC_CONTACT_FORM_ENDPOINT` is `""` in `k8s/configmap.yaml`, so the form falls back to a
|
||||
@@ -124,15 +131,15 @@ mailto handoff. Inbound leads will be lost or awkward on day one.
|
||||
- [ ] Test a real submission end-to-end and confirm `/thank-you/` is reached.
|
||||
- [ ] Confirm the delivery address is monitored.
|
||||
|
||||
### 1.5 Placeholder blog post would go live and be indexed 🛑
|
||||
`src/content/insights/example-draft.md` has `draft: true`, but the flag is **declared in the Zod
|
||||
schema and never enforced** — no `filter` on `getCollection("insights")` in
|
||||
`src/pages/insights/[slug].astro` or the index. Result: `/insights/example-draft/` is built *and*
|
||||
listed in `dist/sitemap-0.xml`, so "Example draft insight" ships to Google.
|
||||
- [ ] Either filter drafts out of `getCollection` (both the index and `getStaticPaths`) — the
|
||||
durable fix — or delete the file.
|
||||
- [ ] Re-run `npm run build` and confirm the URL is gone from `sitemap-0.xml`.
|
||||
- [ ] Decide whether `/insights/` should ship at all with zero real articles (see §3).
|
||||
### 1.5 Draft insight was being published and indexed ✅ FIXED 2026-09-23
|
||||
`src/pages/insights/[slug].astro` called `getCollection("insights")` unfiltered, so the
|
||||
`draft: true` placeholder built to `/insights/example-draft/` **and** appeared in
|
||||
`sitemap-0.xml`. The schema declared the flag and `rss.xml.ts` already honoured it — only the page
|
||||
route ignored it. Filtered in `getStaticPaths`, matching the RSS pattern. Build is 21 → 20 pages
|
||||
and the URL is gone from the sitemap. Commit `4e354d2`.
|
||||
|
||||
- [ ] 🛑 **Still open (owner):** whether `/insights/` should ship at all with zero real articles.
|
||||
It is currently in the primary nav. See also §2.5.
|
||||
|
||||
### 1.6 Canonical host is undecided 🛑 owner
|
||||
The ingress answers on **both** apex and `www`; `astro.config.mjs`, `robots.txt`, and the
|
||||
@@ -146,6 +153,35 @@ hosts with no redirect splits SEO signal from day one.
|
||||
|
||||
## 2. Should-fix before cutover
|
||||
|
||||
### 2.5 `/insights/` index still renders developer-facing copy
|
||||
Found while fixing §1.5. `src/pages/insights/index.astro` shows visitors two cards written for a
|
||||
developer, not a reader:
|
||||
- *"Publishing path"* — "Future posts can be added as Markdown or MDX in
|
||||
`src/content/insights` with typed frontmatter for title, description, publish date…"
|
||||
- *"RSS support"* — "The feed is ready for future article imports even though no public posts are
|
||||
published yet."
|
||||
|
||||
The hero also announces the section as a "Future publishing home", i.e. it tells visitors the
|
||||
section is empty. Same defect class as §1.3, but left alone deliberately: what the page *should*
|
||||
say depends on the owner's call in §1.5 on whether `/insights/` ships at all.
|
||||
|
||||
- [ ] If `/insights/` ships: delete both note-cards and rewrite the hero as reader-facing copy.
|
||||
- [ ] If it does not: drop it from the primary nav and exclude the route from the sitemap.
|
||||
|
||||
### 2.6 Staging URL ✅ LIVE 2026-09-23
|
||||
**https://bcs.int.7tl-homelab.com** — review the rebuild in a browser, valid cert, no warning.
|
||||
|
||||
- LAN-only: `*.int.7tl-homelab.com` resolves to the internal traefik LB (10.66.15.30). Not
|
||||
reachable from the internet; the real domain is untouched and WordPress still serves it.
|
||||
- Cert issued by Let's Encrypt via cert-manager DNS-01 in ~75s, `CN=bcs.int.7tl-homelab.com`,
|
||||
valid to 2026-12-21, auto-renewing.
|
||||
- All 9 public routes verified 200.
|
||||
- Commit `171c8c9`. Note it also corrected the issuer name in `k8s/ingress.yaml`: the commented
|
||||
placeholder said `letsencrypt-production`, but the ClusterIssuer is **`letsencrypt-prod`** —
|
||||
uncommenting it as written at cutover would have silently failed to issue.
|
||||
- ArgoCD may take a few minutes to poll a push; force it with
|
||||
`kubectl annotate application bcs-website -n argocd argocd.argoproj.io/refresh=hard --overwrite`.
|
||||
|
||||
### 2.1 e2e suite is red — stale assertions, not a regression
|
||||
4 of 46 tests fail. Both failures assert **invented copy that the exact-copy work correctly
|
||||
removed**:
|
||||
|
||||
Reference in new issue
Block a user