Commit Graph
94 Commits
Author SHA1 Message Date
hoelee 2df67b6c50 Fix listing sort order: order by pubDate, matching the date displayed
Deploy / build (push) Successful in 36s
Listings render `pubDate` but sorted by `updatedDate ?? pubDate`, so any
post carrying both dates sorted by a date it never displayed. After the
backdate commit the two diverged by years and the list read out of order
("January 7, 2026" above "September 13, 2026", "March 11, 2026" below
"December 10, 2025").

Replace `sortByUpdated` with `sortForListing`, which orders by `pubDate`
and uses `updatedDate` only as a tiebreak. This matches the RSS feed,
which already sorted by `pubDate`.

Verified all three listings (EN, EN homepage, ZH) are monotonically
non-increasing across the full 2024-09 -> 2026-09 span.
2026-09-21 21:57:10 +08:00
hoelee ae2ccedaad Backdate evergreen posts to build a real archive span (EN+ZH)
Deploy / build (push) Successful in 1m2s
11 evergreen posts had no date- or version-sensitive prose, but all
carried September 2026 publish dates, making the archive look like it
started two weeks ago. Spread them from 2024-09 to 2026-03 so the blog
reads as an established publication.

Per post-guideline.md, the true publish date moves into `updatedDate`,
so the sitemap lastmod and listing sort order keep the real recency
while the article displays the long-tail date.

Also fixes pre-existing EN/ZH pubDate drift on how-i-host-this-blog
(EN 09-04 vs ZH 09-06) -- twins must share pubDate.

Posts left untouched pin themselves in prose (e.g. "In September 2026
a Seagate IronWolf 110...", prompt-expiry dates, model release dates).
2026-09-21 21:36:41 +08:00
hoelee 473a20edf7 Add post: Why I Still Bought a GPU to Run AI When Claude and GPT Are Stronger (EN+ZH)
Deploy / build (push) Successful in 5m13s
2026-09-21 21:17:55 +08:00
hoelee 01672cf6ee Draft: the > character that broke authentik brand CSS (EN+ZH)
Deploy / build (push) Successful in 23s
Held unpublished (draft: true). Records the u003e escaping bug:
authentik renders > in branding_custom_css as the literal text
u003e, so any child combinator produces an invalid selector that
silently matches nothing. Includes the cssRules-based debugging
order and the character safety probe.

Docs: not yet recorded in project-state.md
2026-09-20 09:53:01 +08:00
hoelee 378aff24d0 docs: check off Workbench/MariaDB gotcha post (B2)
Deploy / build (push) Successful in 16s
2026-09-20 04:20:45 +08:00
hoelee a9a91a25d4 Draft bank: 2 CodeIgniter posts (EN+ZH), held unpublished
Deploy / build (push) Successful in 18s
Two finished posts written from the numerology-report migration work, kept as
draft: true so they build no pages and appear in no listing until published.
Content bank for weeks when there is nothing fresh to write.

- migrating-codeigniter-iis-to-openlitespeed (engineering)
  IIS -> OpenLiteSpeed/CyberPanel. The two fatals that only appeared once the
  authentik SSO gate was gone, the docroot public/ separation, and the
  loopback self-call that becomes a real outbound HTTPS request on LiteSpeed.
- upgrading-codeigniter-46-to-47 (notes)
  The two fatal config properties NOT in the official upgrade guide
  (permittedURIChars, jsonEncodeDepth), why Composer never merges app/Config,
  and the property-diff script that finds the whole class of problem at once.

Both fill the starved engineering (1 post) and notes categories. project-state.md
records them as Step B2b with the publish checklist.
2026-09-20 04:19:37 +08:00
hoelee a1488da2d8 Add post: When Your Database Client Lies to You (Workbench 26 / MariaDB)
Deploy / build (push) Successful in 22s
EN + ZH devops gotcha post on debugging MySQL Workbench 26.7.0's failure
to connect to MariaDB. Three patches to Oracle's bundled code, all the
same root cause: `major >= 8` is not a valid MySQL-vs-MariaDB test.

Also adds per-post OG + banner (TERMINALS/BANNERS entries).
2026-09-20 04:18:11 +08:00
hoelee 060b0f1733 docs: record robots.txt encoding rule and sitemap derivation in seo-reference
Deploy / build (push) Successful in 19s
The crawler/sitemap mechanics now live in the repo doc, not just in the
commit log: robots.txt is a build-time endpoint that must stay pure ASCII
(no charset on a text/plain response means non-ASCII renders as mojibake),
the policy is allow-all with enforcement deliberately left to Cloudflare,
why writing a real robots.txt demotes Cloudflare's placeholder from
replacement to prepend, and that lastmod/hreflang are derived so they must
never be hand-authored.
2026-09-19 22:14:40 +08:00
hoelee e18c322538 SEO: sitemap lastmod + hreflang alternates; robots.txt allows all crawlers
Deploy / build (push) Successful in 24s
robots.txt carried a UTF-8 em dash in its header comment, which renders as
mojibake ("鈥�") in clients that read text/plain as a legacy codepage. The
file is now pure ASCII (verified with `LC_ALL=C grep '[^ -~]'`), and the
encoding trap is documented in the endpoint so it does not come back.

Policy change to allow-all: the previous version blocked CCBot, Bytespider,
Amazonbot and Applebot-Extended. Training crawlers are now welcome too - the
blog benefits from being read, and robots.txt is advisory anyway (Cloudflare
documents it as unenforced; AI Crawl Control is the enforcement layer).
Drops the Content-Signal directives along with the blocklist.

Sitemap gains both fields Google actually uses:
- lastmod on all 58 post URLs, from updatedDate ?? pubDate, read straight
  from the markdown frontmatter at config-eval time (the sitemap runs in
  astro:build:done, after the content collection is gone).
- xhtml:link hreflang alternates on all 77 URLs, pairing EN/ZH twins.
  /posts/ is special-cased: it has no /zh/posts/ twin, the Chinese post
  listing IS the /zh/ homepage, so the pair is declared rather than derived.
  Verified programmatically that every emitted alternate resolves to a page
  that is actually built and present in the sitemap.
2026-09-19 22:03:37 +08:00
hoelee 7e0802f913 SEO: real robots.txt + hreflang pairs + BlogPosting schema
Deploy / build (push) Successful in 18s
robots.txt was absent at the origin, so Cloudflare served its Free-plan
Content Signals Policy placeholder — a file with no User-agent, no Sitemap
and no directives. Adds src/pages/robots.txt.ts (origin 200 → CF merges
instead of substituting) pointing at sitemap-index.xml, disallowing
/pagefind/, and expressing search=yes / ai-input=yes / ai-train=no in line
with the two-lane SEO+GEO strategy in docs/seo-reference.md. Citation
crawlers (Google-Extended, OAI-SearchBot, PerplexityBot, ClaudeBot) stay
allowed; only training-only harvesters blocked.

hreflang was never emitted despite full EN/ZH i18n: both language versions
sat in the sitemap with no cross-reference. BaseLayout gains altLocaleUrl
and emits en/zh/x-default per page; every post pair, category pair, and
landing page now cross-links.

Also adds BlogPosting JSON-LD (@id-linked to the site-wide Person node)
so Google has a rich-result-eligible node per article, and creates the
missing /zh/about/ page — the EN about page pointed its language switch at
a 404, and /about/ was the only unpaired page after hreflang landed.
2026-09-19 21:41:22 +08:00
hoelee 86f3a977b9 Fix gpg command mangled by Cloudflare email obfuscation
Deploy / build (push) Successful in 19s
Cloudflare's Email Address Obfuscation rewrites literal email
addresses into [email protected] with a data-cfemail payload, which
broke the gpg --locate-keys line inside the code block - readers
copying the shell command got garbage. Replaces it with a
comment pointing at the .asc link and the published fingerprint.
2026-09-19 21:16:17 +08:00
hoelee a0c22f22ca Add beginner Tor Browser walkthrough to onion service post
Deploy / build (push) Successful in 24s
Readers arriving at the onion addresses had no instructions for
opening a .onion. Adds a step-by-step Tor Browser install (download,
GPG signature verification, connect, bridge fallback) plus how to
open a v3 address: 56-char base32 rules, no typo correction, v2
retirement, and the 10-60 minute descriptor propagation window.

Mirrored to the Chinese version in the same commit.
2026-09-19 21:14:17 +08:00
hoelee ab16b8f935 docs: record RDPGuard/IPBan gotcha post in B2 backlog
Deploy / build (push) Successful in 19s
2026-09-19 19:53:27 +08:00
hoelee daca86dc43 Add post: Replacing RDPGuard With IPBan (EN + ZH, og+banner)
Deploy / build (push) Successful in 22s
Case study of migrating from paid RDPGuard 7.8.7 to open-source IPBan
4.1.0, covering the three undocumented traps: the uninstaller that would
have silently unbanned 12 active attackers, the non-existent
--install-service flag in v4.1.0, and ExpireTime vs BanTime.

Also fixes an og-gen defect: the tag chip hardcoded KIND='DevOps', so
every non-devops post carried a wrong label (e.g. "case-studies · DevOps"
on the STT card). KIND now derives from the post category, and all 29
existing OG images are regenerated with correct badges.
2026-09-19 19:50:27 +08:00
hoelee 8cebe20981 Merge GitHub main: keep both OG/banner entries (TRIM, SATA cable, STT)
Deploy / build (push) Successful in 17s
2026-09-19 07:56:53 +08:00
hoelee 9fa366a0ac Add case study: self-hosted speech-to-text API (EN + ZH)
Deploy / build (push) Successful in 25s
New flagship case study covering a GPU-backed whisper.cpp transcription API
reachable from Windows, iPhone, iPad and Android behind an authenticated
gateway — framed as a service offering with the office-productivity case
(roughly 5x typing throughput, unlimited, audio never leaves the premises).

Content:
- EN + ZH posts (same slug -> auto language switch)
- "Why it matters" opener, hire CTA with clickable WhatsApp + mailto
- Four documented traps: incomplete CUDA component selection, loopback bind
  mistaken for a firewall problem, n8n Code nodes discarding binary + the
  data0 key name, and nginx default.conf hijacking port 80
- Honest scoping of the auth model (access control, not hardened public API)

Assets:
- Custom OG image + 16:9 banner (generator entries appended, not patched
  inside the template-literal maps)

Also marks Mem0 (B1) done and adds B1b to project-state.md.
2026-09-19 07:55:29 +08:00
hoelee 044ded45b3 Add TRIM corruption sequel post + publish SATA cable post (en/zh, og+banner)
Deploy / build (push) Successful in 19s
- New post: 'The Corruption Came Back on Different Drives — the Cause Was
  TRIM, Not the SSDs' — same 0x8941f998 zeros fingerprint on a second drive
  stack (IronWolf 110 SATA pair), root cause queued TRIM (FreeBSD gag 264139),
  fix diskAutotrim=off + nodiscard, scrub evidence, enterprise SATA buying
  guidance. en + zh, custom OG + banner.
- Publish formerly-draft SATA cable post (draft:false) with OG + banner.
- Correct drive identity in both: ZA960NM10001 is Seagate IronWolf 110, not
  'Samsung PM9A3' (PM9A3 is NVMe; FPDMA errors are SATA-only).
- Old RAID post (en+zh): cross-link to sequel, fix 'a Samsung' -> IronWolf 110.
2026-09-18 05:38:13 +08:00
hoelee fb66e17b50 posts: n8n v1→v2 migration, self-healing entitlements, TTS sidecars
Deploy / build (push) Successful in 19s
Three new posts (EN + ZH twins, og + banner each):

- n8n-v1-to-v2-upgrade-gotchas (devops): the seven deprecations that
  surfaced upgrading 1.123.x → 2.40.1, decoded from the boot log —
  telemetry schema rejection, N8N_WEBHOOK_URL rename, internal runner
  deprecation, task timeout 300s→60s, two compression limits, v3
  storage rename, plus the DB override that silently disabled the
  AI sandbox.
- self-healing-digital-goods-entitlements (case-studies): the W1–W5
  NocoDB → n8n → AList entitlement lifecycle. Build-time code sharing
  for n8n Code nodes, MAX-expiry semantics, dry-run safety, daily
  drift repair, CORS-not-HMAC reasoning, and the public→internal
  NocoDB cascading-failure fix (504 → retry storm → 503).
- running-tts-as-a-service-with-token-sidecars (ai): a year-long TTS
  service built on two cron containers that refresh Azure/Google
  tokens into a shared file, with the speed/voice mapping layer.

banner-gen: center terminal body vertically so line counts shorter
than the fixed 690px panel don't leave a dead void at the bottom.
Verified via DOM measurement (gapAbove 104 / gapBelow 106).
2026-09-18 01:51:46 +08:00
hoelee be37348a8c post: add missing Chinese translation of hello-world (restores 22/22 EN-ZH parity)
Deploy / build (push) Successful in 17s
2026-09-18 01:34:57 +08:00
hoelee 937a114e30 post: shipping an AI photo editor as a WordPress plugin (case study, EN+ZH, og+banner)
Deploy / build (push) Successful in 20s
2026-09-18 01:31:46 +08:00
hoelee 4e2e603449 post: shipping an AI photo editor as a WordPress plugin (case study, EN+ZH, og+banner) 2026-09-18 01:30:04 +08:00
hoelee cdc3475f61 Fix og-gen: Chrome headless truncates 630px card footer; capture at 900 and crop with sharp, pin footer via absolute pos
Deploy / build (push) Successful in 15s
2026-09-16 01:21:25 +08:00
hoelee 55619aa04e Add posts: RAID silent corruption + self-hosted mem0 (en/zh, og+banner)
Deploy / build (push) Successful in 20s
2026-09-16 01:04:41 +08:00
hoelee 0dee1ea173 post: unraid array-stop swapfile hang root cause + User Scripts fix (en+zh, OG+banner)
Deploy / build (push) Successful in 1m1s
2026-09-15 18:44:09 +08:00
hoelee 53f1ec5de7 project-state: mark C3 done, C4 partially done (zh categories live, zh posts pending)
Deploy / build (push) Successful in 18s
2026-09-14 00:14:56 +08:00
hoelee 12529e0cd0 posts: reframe marketplace scraper as client work (used-electronics reseller), en+zh + OG image
Deploy / build (push) Successful in 18s
2026-09-14 00:09:45 +08:00
hoelee 4cf52e04c1 Categories page: descriptions, per-category terminal illustrations, full ZH version
Deploy / build (push) Successful in 17s
- 7 categories now listed with name, blurb, post count and a
  per-category terminal-style SVG illustration (CategoryArt)
- empty categories show '0 posts · coming soon' (non-link, no soft-404)
- new zh pages: /zh/categories/ index + /zh/categories/[category]/ detail
- PostList is locale-aware (zh-CN dates, zh category links)
- zh nav '分类' now points to /zh/categories/
- category detail pages get art + description header
- language switch wired both ways (EN <-> ZH)
2026-09-13 23:50:08 +08:00
hoelee 730a936137 Add scraping bot-walled marketplace warm-browser-session deep-dive (en + zh + OG)
Deploy / build (push) Successful in 17s
2026-09-13 23:33:26 +08:00
hoelee f0819eb3a3 post: passbolt hang three failure modes (devops gotcha, EN+ZH, og+banner)
Deploy / build (push) Successful in 16s
2026-09-13 17:20:42 +08:00
hoelee 249b32b5d9 Add OG image + banner for Chinese LLM APIs post (EN + ZH)
Deploy / build (push) Successful in 16s
2026-09-11 19:57:33 +08:00
hoelee da60e08e20 Add post: Using Chinese LLM APIs from Malaysia (EN + ZH)
Deploy / build (push) Successful in 14s
2026-09-11 19:01:49 +08:00
hoelee f41a6bdb1e post: add LTX-2.3 ComfyUI workflow breakdown + exact prompt to AI video guide (en + zh)
Deploy / build (push) Successful in 16s
2026-09-11 18:47:16 +08:00
hoelee 63029ddefd Add guide: Best AI video generators 2026 free vs paid + LTX-2.3 test (en + zh)
Deploy / build (push) Successful in 14s
2026-09-11 18:27:38 +08:00
hoelee 8e595d0f93 post: how I made my own songs with Suno AI (case study with embedded players + LRC sync, EN+ZH)
Deploy / build (push) Successful in 15s
2026-09-11 16:36:01 +08:00
hoelee 30a1963bea Add case study: AI furniture compositing with FLUX.1 Kontext (en + zh)
Deploy / build (push) Successful in 15s
2026-09-11 12:19:16 +08:00
hoelee 2645f778b2 Add case study: syncing a self-improving AI agent across machines (en + zh)
Deploy / build (push) Successful in 19s
2026-09-11 12:12:55 +08:00
hoelee 89a46451f4 post: add Tor/onion primer at top + service CTA with contact links (en + zh)
Deploy / build (push) Successful in 1m27s
2026-09-09 09:56:29 +08:00
hoelee 010306f01f assets: regenerate og+banner via official og-gen/banner-gen with per-post terminal entries
Deploy / build (push) Successful in 58s
2026-09-09 09:47:41 +08:00
hoelee 0da3ea5768 post: darknet-curiosity intro with live portfolio/gitea onion mirrors, og+banner images (en + zh)
Deploy / build (push) Successful in 2m35s
2026-09-09 09:41:38 +08:00
hoelee 383e46cd0c post: single obfs4 mention (reading-online only)
Deploy / build (push) Successful in 55s
2026-09-09 09:20:01 +08:00
hoelee 3503bb22b8 post: reframe as onion-only hosting exploration, add service-offering + vanity mining section (en + zh)
Deploy / build (push) Successful in 1m2s
2026-09-09 09:17:45 +08:00
hoelee b3f45bfc0d post: Hardening a Tor Onion Service: What Actually Matters (en + zh)
Deploy / build (push) Successful in 1m26s
2026-09-09 09:07:04 +08:00
hoelee 6aa9105460 Add CyberPanel v2 API reverse-engineering post (EN + ZH)
Deploy / build (push) Successful in 44s
2026-09-09 07:53:07 +08:00
hoelee 618b01e4bd feat: show 4 related posts; title-case 'Related Posts'
Deploy / build (push) Successful in 37s
2026-09-09 07:37:53 +08:00
hoelee 98b50af6be docs: document 16-day 404 cache pitfall in ops runbook
Deploy / build (push) Successful in 41s
2026-09-09 07:35:48 +08:00
hoelee 3d5e75aa70 Add case study: vetted 20 VPS providers with parallel subagents (EN + ZH + OG + banner)
Deploy / build (push) Successful in 1m5s
2026-09-09 07:28:03 +08:00
hoelee f378b4f58d Add OG image + banner for hosting-provider verification post
Deploy / build (push) Successful in 33s
2026-09-09 07:23:32 +08:00
hoelee ffb2dbe15a Add post: How to Verify a Hosting Provider Before You Buy (EN + ZH)
Deploy / build (push) Successful in 49s
2026-09-09 07:19:49 +08:00
hoelee 62b681bad1 Add two posts: headless-browser scraping limits + NocoDB backfill gotchas
Deploy / build (push) Successful in 1m12s
- why-your-headless-browser-cant-scrape-everything (case study, en+zh)
- the-nocodb-attachment-that-wouldnt-update (note, en+zh)
- og + banner images for both, generator entries added
- gitignore .og/ scratch dir (also removes previously-committed scratch files)
2026-09-09 06:56:20 +08:00
hoelee ca88623486 Upgrade Telegram post CTA to one-tap wa.me/mailto links with named service (en+zh)
Deploy / build (push) Successful in 46s
2026-09-09 06:39:45 +08:00