# Cloudflare Deployment Audit — 485Tech.com

**วันที่ตรวจ:** 27 สิงหาคม 2026 (เวลา sandbox)
**เป้าหมาย:** ตรวจ source of truth, auto-build, Worker `home`, build history, custom-domain binding และ live status แบบ read-only โดยไม่แก้ Cloudflare dashboard หรือ deploy production จาก sandbox

## สรุปผู้บริหาร

Cloudflare Workers Builds เชื่อมกับ GitHub จริง: Worker `home` ผูกกับ repository `485Tech.com`, branch `main` และ trigger `Deploy default branch`. Custom domains `485tech.com` และ `www.485tech.com` อยู่ใน environment `production` ของ service `home`. หลังแก้ routing ให้ Worker ทำงานก่อน Static Assets และแก้ immutable `ASSETS` response รอบ final build สำเร็จ และ live probe ผ่านทั้ง route availability กับ security middleware.

> **สถานะปัจจุบัน:** production route, Worker security headers, CSP Report-Only, per-request nonce, HTML `no-store`, canonical URLs และ CI/build pipeline ผ่านหลักฐานที่ตรวจได้. `deployment_id` ใน Workers script metadata ยังว่าง จึงควรให้ owner ยืนยัน version history/rollback record ใน dashboard ก่อนประกาศ operational controls ครบถ้วน.

## ผลตรวจจาก Cloudflare API

เรียก read-only endpoints ของ Workers Builds, Workers scripts, custom domains, zones, DNS และ Worker routes ผ่าน Cloudflare connector โดยไม่ส่ง mutation request และไม่เปิดเผย credentials.

| รายการ | ผลตรวจล่าสุด |
|---|---|
| Worker | `home`; script tag `54b217cc023743b2b993f1e9c56d5f9e` |
| Repository | GitHub `485Tech.com`, provider account `485Tech`, branch `main` |
| Production build configuration | มี configuration; `root_directory: /`, cache enabled, `path_includes: *` |
| Build command | `python3 build.py`; compatibility bridge delegate ไป canonical `npm run build` |
| Dependency install | provider ตรวจพบ npm และรัน `npm clean-install`; npm/package-lock เป็น source of truth |
| Deploy command | `npx wrangler deploy` |
| Main trigger | `Deploy default branch`, branch include `main`, active, push-based |
| Custom domains | `485tech.com` และ `www.485tech.com`, service `home`, environment `production` |
| Zone Worker route patterns | ไม่มี route pattern ใน `/zones/{zone_id}/workers/routes`; binding ใช้ Workers custom domains แทน |
| Latest successful Workers Build | UUID `6631647b-8ee9-41b6-8c11-b1d432178d73`; commit `b63aa65`; `build_outcome: success`; created `2026-08-27T16:13:10.524Z`; stopped `2026-08-27T16:13:47.524Z` |
| Latest code-changing successful build | UUID `35a95605-6ebe-4365-aede-e98f9b6381e3`; commit `4656cf4`; `build_outcome: success`; created `2026-08-27T15:56:31.338Z`; stopped `2026-08-27T15:57:00.838Z` |
| Build metadata | `docs: record final production verification` (latest docs-only build); code path from `fix: harden Worker-first asset routing`; `python3 build.py` → `npx wrangler deploy` |
| Active Worker metadata | `modified_on: 2026-08-27T15:56:58.262946Z` at last code verification; `last_deployed_from: wrangler`; `deployment_id` ว่าง |
| GitHub Actions | run `33092071834` ของ commit `b63aa65` ผ่านทั้ง Static/contract/Worker และ Browser/all-tool jobs; validation-only ไม่ deploy |

ก่อนรอบ final build มี build `b2b6b66` ที่แก้ npm lockfile สำเร็จและ build `9cad346` ที่แก้ immutable response สำเร็จ แต่ live route ยังเกิด 307/1101 เมื่อ Static Assets routing และ HTML handling ไม่ตรงกับ Worker middleware. รอบ `4656cf4` จึงรวม `run_worker_first`, `html_handling = "drop-trailing-slash"`, clean-URL pass-through และ response cloning ไว้เป็นชุดเดียว.

## Repository-side production fixes

`wrangler.toml` ระบุ top-level `name = "home"` ให้ตรงกับ Worker ที่ custom domain ผูกอยู่ และตั้งค่า `assets.run_worker_first = true` เพื่อให้ Worker middleware ทำงานก่อน Static Assets ตามแนวทางของ Cloudflare. ตั้ง `assets.html_handling = "drop-trailing-slash"` ให้ตรงกับ generated canonical URLs เช่น `/tools/json` และ `/tools/batch-text`.

`src/worker/index.js` ใช้ `env.ASSETS.fetch(request)` ให้ Cloudflare asset router จัดการ clean URL/index semantics แทนการ map `/` ไป `/index.html` เอง ซึ่งอาจคืน redirect กลับ `/`. หลังได้ ASSETS response จะ clone body/status/headers เป็น `new Response(...)` ก่อนเติม security headers เพราะ ASSETS response จริงอาจมี immutable headers; local Worker smoke จำลอง behavior นี้แล้ว.

GitHub Actions `.github/workflows/ci.yml` คงเป็น validation-only และไม่มี Cloudflare credential/deploy step. Workers Builds เป็น production deployment source of truth เพียงทางเดียว เพื่อป้องกัน race condition ระหว่าง deploy paths.

## GitHub Actions และ local evidence

Run `33092071834` ผ่านครบ 2 jobs:

| Job | ผลตรวจ |
|---|---|
| Static, contract and Worker checks | ผ่าน; build generated assets, generated-tree check, catalog/capability/docs, syntax, unit, Background Remover, Worker security smoke และ whitespace |
| Browser and all-tool regression | ผ่าน; preview, smoke ทุก tool, functional audit, matrix, deep sweep, UI regression, named snapshot QA และ capability details QA |

Local preflight รอบ final ที่ผ่าน ได้แก่ `npm ci --ignore-scripts`, `python3 build.py`, `npm run validate:tools`, `npm run validate:docs`, `node scripts/validate_syntax.mjs`, `node scripts/unit-app-test.mjs`, `node scripts/bg-remover-test.mjs`, `node scripts/worker-smoke.mjs` ได้ 54/54, `git diff --check` และ `CI=1 npx --yes wrangler@4.127.0 deploy --dry-run --env production`. Worker smoke มี immutable-ASSETS regression fixture เพื่อจับ 1101 จากการ mutate response headers.

## Production live probe — หลัง build 6631647b

ตรวจด้วย GET แบบ read-only หลัง latest docs-only Workers Build หยุดที่ `2026-08-27T16:13:47.524Z` และยืนยันซ้ำหลัง code build `35a95605`. ทุก route สำคัญตอบตาม policy และไม่พบ `1101`.

| Route | HTTP | ผลตรวจ |
|---|---:|---|
| `/`, `/tools`, `/use-cases` | 200 | HTML ตอบได้ |
| `/sitemap.xml`, `/ads.txt`, `/manifest.webmanifest` | 200 | asset/metadata ตอบได้ |
| `/tools/json`, `/tools/batch-text` | 200 | canonical no-slash standalone pages |
| `/tools/json/`, `/tools/batch-text/` | 307 | redirect ไป canonical no-slash URL |

### Production security headers

GET `/` ตอบ `200`, `content-type: text/html` และมีค่าที่ Worker กำหนดครบ:

| Header/invariant | ผลตรวจ |
|---|---|
| `Strict-Transport-Security` | `max-age=86400; includeSubDomains` |
| `Content-Security-Policy-Report-Only` | มี; ไม่มี enforce จนกว่าจะ review reports 7–14 วัน |
| CSP nonce | body มี nonce ใน script tags และค่า nonce ตรงกับ CSP header |
| `X-Content-Type-Options` | `nosniff` |
| `X-Frame-Options` | `SAMEORIGIN` |
| `Referrer-Policy` | `strict-origin-when-cross-origin` |
| `Permissions-Policy` | baseline deny policy ครบ |
| `Cross-Origin-Opener-Policy` / `Cross-Origin-Resource-Policy` | `same-origin` / `same-origin` |
| `Reporting-Endpoints` | `csp-endpoint="/api/csp-report"` |
| HTML cache policy | `Cache-Control: no-store` |
| Nonce sample | body 4 script tags / 4 nonce tags; body nonce ตรงกับ CSP nonce |

ผลนี้แก้ gap ของรอบ b2b6 ที่ asset-first bypassed Worker และรอบ 4a2 ที่เปิด Worker-first แล้วชน immutable headers/redirect loop.

## Definition of done สำหรับ production deployment

1. Workers Builds เชื่อม repository/branch จริงและ build ของ commit ล่าสุด success — **ผ่าน**.
2. Deploy command target Worker ที่ custom domain ใช้งาน — **ผ่านจาก custom-domain binding และ live Worker headers**.
3. Routes สำคัญ, sitemap, ads.txt, manifest และ standalone tools ผ่าน status/canonical policy — **ผ่าน**.
4. HTML ผ่าน security headers, CSP mode, nonce parity และ `no-store` — **ผ่าน**.
5. HTML/catalog/sitemap/assets มาจาก generated release ที่ตอบจาก Worker เดียวกัน — **ผ่านตาม build/live markers**.
6. GitHub Actions เป็น validation-only และมี production deploy source เดียว — **ผ่าน**.
7. Active version/rollback record ระบุได้จาก dashboard และมี owner — **ยังต้องให้ owner ยืนยัน** เพราะ script metadata API คืน `deployment_id` ว่าง.

## Known limitations / owner follow-up

CSP ยังคงเป็น Report-Only ตาม rollout ที่ตั้งใจไว้; ต้อง review CSP reports อย่างน้อย 7–14 วันก่อนเปลี่ยน `CSP_MODE` เป็น enforce. HSTS ใช้ ladder เริ่มที่ 1 วันและยังไม่เปิด preload. D1/KV bindings สำหรับ subscribe, CSP report persistence และ rate limiting ยังเป็น optional infrastructure ที่ต้อง owner ตั้งค่าเมื่อพร้อม.

AdSense เป็น consent-gated และ non-personalized default. การมี `ads.txt` ตอบ 200 ไม่ใช่หลักฐานว่าโฆษณา serve แล้ว; owner ยังต้องยืนยัน AdSense site ownership/account, Google Privacy & Messaging หรือ CMP และ production behavior ด้วยตนเอง.

## ข้อสรุป

รอบ final ทำให้ 485Tech.com **พร้อมใช้งาน production ตามหลักฐาน route, build, CI และ Worker security ที่ตรวจได้**. จุดสำคัญไม่ใช่เพียง build success แต่คือการตรวจพบและแก้ลำดับปัญหาจริง: asset-first bypassed middleware, `run_worker_first` ทำให้ immutable response mutation เกิด 1101, และ built-in HTML handling ทำให้ canonical redirect loop. หลังเพิ่ม Worker-first, drop-trailing-slash และ response cloning แล้ว code build `4656cf4` สำเร็จ, docs-only build `b63aa65` สำเร็จ และ live probe หลัง b63 ผ่านครบ. เหลือเพียง owner operational follow-up เรื่อง active version/rollback record, CSP report review, environment bindings และ AdSense account/CMP verification.

## References

[1]: https://developers.cloudflare.com/workers/ci-cd/builds/git-integration/github-integration/ "Cloudflare Workers — GitHub integration"
[2]: https://developers.cloudflare.com/api/operations/workers-builds-get-worker-build-configuration "Cloudflare API — Get worker build configuration"
[3]: https://developers.cloudflare.com/api/operations/workers-builds-get-worker-triggers "Cloudflare API — Get worker triggers"
[4]: https://developers.cloudflare.com/workers/static-assets/routing/worker-script/ "Cloudflare Workers — Worker script and run_worker_first"
[5]: https://developers.cloudflare.com/workers/static-assets/routing/advanced/html-handling/ "Cloudflare Workers — HTML handling"
