Commit Graph
117 Commits
Author SHA1 Message Date
hoelee 8f3befaf72 docs: stats.hoelee.com hardening (A+B) — rotate password/APP_SECRET, add the umami-gateway, dashboard LAN-only, tracker verified end-to-end
Deploy / build (push) Successful in 21s
2026-09-29 05:12:31 +08:00
hoelee ca02aaa624 docs: stats.hoelee.com is live via DNS+DSM reverse proxy (not CF) — record the exposure path, the client-IP header fix, and the open default-credential item
Deploy / build (push) Successful in 34s
2026-09-29 04:35:41 +08:00
hoelee 2beea7b219 docs: record the self-hosted Umami deployment (E1) and what is still blocked on Cloudflare
Deploy / build (push) Successful in 23s
2026-09-29 04:16:57 +08:00
hoelee b0ada17fa7 docs: live re-audit (2026-09-29) + Phase E distribution backlog
Deploy / build (push) Successful in 29s
Re-checked the Sept research against the live site and the repo:
- 53 posts x 2 languages, 127 sitemap URLs, 133/133 internal links 200
- Mark C1 (per-post OG), D1 (search), B2b (draft bank) as done — they were stale as open
- New Phase E (top of the queue): E1 analytics (CF Web Analytics + GSC), E2 main-site ->
  blog link (deferred to the www.hoelee.com overhaul), E3 dev.to syndication, E4 ZH nav +
  /zh/posts/, E5 og:locale, E6 Cloudflare HTML caching, E7 volume guardrail, E8 hygiene
- New section 4: measured evidence table; conventions section renumbered
2026-09-29 03:07:51 +08:00
hoelee 95b21e3456 Add 5 posts (EN + ZH): fully on-chain SVG NFTs, the CRLF art trap, a Chainlink VRF v2.5 lottery, page-by-page PDF verification, JPA @Version
Deploy / build (push) Successful in 20s
Five posts with custom OG + banner and hire CTAs. Three are web3, giving
that category its first posts — /categories/web3/ previously 404'd while the
index advertised it as '0 posts - coming soon'.

Backdated where the work genuinely is older: the foundry-nft and
hardhat-smartcontract-lottery commits date to 2024-08-15..19, so those two
posts fill the empty 2024-10 and 2024-12 archive months with updatedDate
holding the real date. The two 2026-08-19 posts use their real work date.

TERMINALS/BANNERS entries for all five slugs are committed this time (both
generators were clean; diffs verified purely additive).
2026-09-29 02:41:58 +08:00
hoelee 9889ef58f8 Backdate 2 of the 6 posts dated 2026-09-29 into empty archive months (EN + ZH)
Deploy / build (push) Successful in 18s
2026-09-29 01:54:39 +08:00
hoelee 6963c4a22d Link the container-docs post to the Synology spreadsheet API flagship (EN + ZH)
Deploy / build (push) Successful in 17s
2026-09-29 01:45:25 +08:00
hoelee 48472e0daa Add 3 posts (EN + ZH): the Synology Spreadsheet API container, the 401-with-correct-password gotcha, and reading a container's own API docs
Deploy / build (push) Successful in 24s
2026-09-29 01:43:00 +08:00
Hermes Agent d88a5f6f2c docs: record the two agent-safety/CDP posts in the project state (Step B2f)
Deploy / build (push) Successful in 29s
2026-09-29 01:40:57 +08:00
Hermes Agent 170f5ccb3f Add 2 posts (EN + ZH): agent-managed Shopee vouchers (propose mode) + why CDP clicks silently fail
Backdated into the empty 2025 stretch of the archive (pubDate 2025-07-08 / 2025-03-19)
with the real date kept in updatedDate 2026-09-29 so sitemap lastmod stays honest.
Custom OG + banner for both; no date- or version-pinned prose in either post.
2026-09-29 01:40:19 +08:00
hoelee e8c5124db1 Add 4 monitoring posts (EN + ZH): smartctl exit 32, Grafana no-data variable, percentage alert thresholds, one Prometheus for 3 hosts
Deploy / build (push) Successful in 28s
Backdated into the 2026-03-25 -> 2026-09-04 archive gap (pubDate 2026-04-14/05-17/06-24/07-29)
with updatedDate 2026-09-29 holding the real date, so sitemap lastmod stays honest.
Custom OG + banner per post, hire CTA, language switch verified.
2026-09-29 01:37:23 +08:00
hoelee d588e9691b docs: record the two SSO posts in the project state (Step B2e)
Deploy / build (push) Successful in 34s
2026-09-29 01:15:48 +08:00
hoelee 2d0de72f51 Add post: NocoDB SSO Is a Licensed Feature (EN + ZH)
Deploy / build (push) Successful in 25s
2026-09-29 01:14:17 +08:00
hoelee e7e4ee58ef Add post: The Forward-Auth Gate That Verified Perfectly — and Wasn't Live (EN + ZH) 2026-09-29 01:14:17 +08:00
hoelee 8dbf124437 Fix pubDate to the actual publish date (2026-09-29) for the Chrome tabs post
Deploy / build (push) Successful in 17s
2026-09-29 01:12:42 +08:00
hoelee 893675e6a3 Add post: Why Chrome Forgets Its Tabs in a Container (EN + ZH)
Deploy / build (push) Successful in 17s
- docker/Chrome/CDP gotcha: the container kills the browser, so it never exits
  cleanly and no restore mechanism fires (flag, Preferences, managed policy all
  verified failing) -> 60s snapshot + replay keeper
- also covers the stale Singleton* lock and custom-cont-init.d permission traps
- custom OG + banner art, EN + ZH, backlog B2 updated
2026-09-29 01:10:39 +08:00
hoelee 1951b02df8 docs: record the dependency-vetting post in the project state (Step B2d)
Deploy / build (push) Successful in 16s
2026-09-29 01:09:39 +08:00
hoelee 87111360ce Add post: How I Vet an Open-Source Dependency Before Betting On It (EN + ZH)
Deploy / build (push) Successful in 15s
New `devops` post on vetting an upstream dependency before building on it:
the six checks that corrected six assumptions from a 1,306-line architecture
spec — repo vital signs via the GitHub API, grepping for the feature instead
of reading for it (OIDC/SSO/SAML → 0 hits), reading a feature doc's target
branch (white-label lives on `multi-tenant`, not `main`), reading the data
model rather than the feature list (percent/fixed vs five assumed rule types),
the Community-vs-Enterprise tier gate (API tokens free, SSO paid), and whether
the money rail works in-country (selfhost + manual payouts, not Stripe Connect).
Closes with the fallback question and the authentik proxy-provider answer.

- EN: src/content/posts/vetting-an-open-source-dependency-before-you-bet-on-it.md
- ZH: src/content/posts/zh/<same slug>.md (same filename → auto language switch)
- Custom OG (1200x630) + banner (1600x900) art via TERMINALS/BANNERS entries
- pubDate 2026-09-29; build verified 93 pages, 17/17 content checks, listing
  order monotonic on /posts/, / and /zh/

Note: the generator maps also carry two entries belonging to parallel
in-flight posts (adding-english-mode…, and the sessions' other slugs);
their post files were left uncommitted.
2026-09-29 01:07:43 +08:00
hoelee a77fb0b5d3 docs: record the English-mode post in the project state
Deploy / build (push) Successful in 28s
2026-09-29 01:06:14 +08:00
hoelee 8a9ba6af1b Add post: No API for Browser Translation (EN + ZH)
Deploy / build (push) Successful in 23s
2026-09-29 01:02:42 +08:00
Hermes Agent 416246cc68 Publish the two CodeIgniter draft posts (EN+ZH) with OG + banner art
Deploy / build (push) Successful in 24s
- migrating-codeigniter-iis-to-openlitespeed (engineering): the two fatal errors
  IIS + SSO had been hiding (env() called from Constants.php; parent::__construct
  in a controller) — both only surfaced on the first unauthenticated request
- upgrading-codeigniter-46-to-47 (notes): the two undefined config properties the
  official upgrade guide cannot warn about (Config\App::$permittedURIChars,
  Config\Format::$jsonEncodeDepth)
- both flipped draft:true -> false, pubDate 2026-09-20 -> 2026-09-27 (real publish date)
- generated 1200x630 OG cards + 1600x900 banners for both slugs
- verified before commit: EN+ZH pages build, language switch links both ways,
  listing order stays monotonic on /posts, /zh and the homepage, banner terminal
  panel centred (gapAbove 102 / gapBelow 104) with no overflow
2026-09-29 01:01:42 +08:00
hoelee d1c040d648 Add post: A Read-Only NocoDB Dashboard for a Database on Another Machine
Deploy / build (push) Successful in 28s
EN + ZH twins. The recipe for pointing NocoDB at a MySQL/MariaDB database on
another machine: the Docker SNAT source-IP trap (the DB sees the host IP, not
the container IP), a SELECT-only grant restricted to that one host, the async
source-creation API with no job-status route, the auto-sync that makes a manual
table step unnecessary (and the create-table route that makes junk tables), and
what a read-only source costs (no metadata edits, UTC-labelled DATETIMEs).

Also adds the og-gen TERMINALS and banner-gen BANNERS entries for the slug
(keeping the sibling session's entries untouched) and the generated PNGs.
2026-09-29 00:57:57 +08:00
hoelee d634385318 Restore 2026 dates on two version-pinned posts
Deploy / build (push) Successful in 4m22s
how-i-host-this-blog and automating-cyberpanel-without-the-ui backdated
cleanly by prose but describe 2026-era software (Gitea 1.27 /
act_runner 0.2.13; CyberPanel 2.4.4.1), so an older byline contradicted
the body. Put both back on their real 2026-09 dates and drop the
updatedDate that only existed to hold that date.
2026-09-21 22:02:15 +08:00
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