⌨️ Thế Giới Keycap Docs Operations

OPS.md — thegioikeycap.vn

Vận hành hằng ngày: chạy lệnh, xem log, deploy, chẩn đoán. Quy trình test đơn hàng nằm ở docs/TASK_PROTOCOL.md §Quy tắc Test.


Chuẩn bị môi trường

# Nạp secret vận hành (Pancake, Brevo, AllinGo, Cloudflare)
set -a; source /srv/thegioikeycap.vn/.secrets.env; set +a

# Rút gọn WP-CLI cho tiện
cd /srv/thegioikeycap.vn/docker
WP="docker compose exec -T -u www-data php wp --path=/srv/thegioikeycap.vn/www"

⚠️ .secrets.env là chmod 600, chủ sở hữu root, không nằm trong git.


WP-CLI

Luôn chạy trong container php với user www-data — chạy bằng root sẽ tạo file sai quyền và WordPress không ghi được nữa.

$WP plugin list --status=active
$WP option get siteurl
$WP cache flush
$WP rewrite flush

# Truy vấn DB — KHÔNG có `wp db query` (container thiếu mysql client)
$WP eval 'global $wpdb; echo $wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->posts}");'

Docker

cd /srv/thegioikeycap.vn/docker
docker compose ps
docker compose restart php        # sau khi đổi cấu hình PHP
docker compose logs -f php
docker compose exec -T php php -v

Hai service: keycap_php (PHP-FPM 8.3) và keycap_mysql (MySQL 8.4). nginx chạy trên host, không trong compose.

Cấu hình PHP-FPM Pool, RAM & WP-Cron (2026-09-24)

  • FPM Pool & Container RAM: Tăng pm.max_children = 32, pm.start_servers = 8, pm.min_spare_servers = 4, pm.max_spare_servers = 12, pm.max_requests = 2000 qua docker/php/zz-pool.conf. Container limit bộ nhớ tăng lên 2G.
  • PHP memory_limit & OPcache: Nâng memory_limit = 1024M, opcache.memory_consumption = 256M, opcache.max_accelerated_files = 20000 qua docker/php/php.ini và vhost nginx.
  • MySQL InnoDB Buffer Pool: Nâng innodb_buffer_pool_size = 512M, innodb_redo_log_capacity = 256M qua docker/mysql/my.cnf (toàn bộ database ~38MB nằm trọn vẹn trong RAM).
  • WP-Cron CLI: DISABLE_WP_CRON = true trong wp-config.php để giải phóng HTTP worker. Cron hệ thống (root crontab) chạy wp cron event run --due-now mỗi 1 phút qua WP-CLI độc lập.

Log

tail -f /srv/thegioikeycap.vn/logs/php/error.log
tail -f /srv/thegioikeycap.vn/logs/nginx/error.log
tail -f /srv/thegioikeycap.vn/logs/nginx/access.log

⚠️ Không phải lỗi nào cũng vào error.log. ArgumentCountError từng gây HTTP 500 trắng trang giỏ hàng mà log trống trơn. Trang trắng + log sạch không có nghĩa là code đúng — hãy nghi ngờ chữ ký callback.

Log có logrotate. Đường dẫn từng bị sai một lần, kiểm tra nếu log ngừng xoay.


Deploy / cập nhật code

Code chạy trực tiếp từ working tree — không có bước build. Sửa file là có hiệu lực, nhưng:

  • PHP: đợi tới 60 giây (OPcache revalidate_freq=60). Muốn có ngay: docker compose restart php.
  • CSS/JS: PHẢI bump TGK_VERSION trong functions.php. Đây là hằng số CỐ ĐỊNH (không phải filemtime), và nó là toàn bộ chuỗi ?ver= của main.css + main.js. Quên bump thì khách cũ vẫn chạy bản cache cũ — trên máy mình thấy đúng, trên máy khách thì không, và không có lỗi nào để lần ra.
# Ép OPcache nhả ngay
docker compose exec -T php kill -USR2 1 2>/dev/null || docker compose restart php

nginx / SSL

  • vhost đang chạy: docker/nginx-thegioikeycap.vn.CUTOVER.conf
  • Đầu file có ghi quy trình rollback về kiến trúc Astro cũ. Đọc trước khi sửa.
  • Bản lưu Astro: /root/backups/thegioikeycap-astro-frontend-FULL-20260905.tar.gz
  • ACME challenge: /srv/thegioikeycap.vn/.well-known/acme-challenge/

Chụp màn hình + QA hành vi thật (Playwright)

⚠️ Sau migrate VPS 09/2026, đây là công cụ đúng — KHÔNG còn chromium snap. Chromium snap thuộc user root của VPS cũ, không tồn tại ở đây.

Tool có sẵn: /opt/screenshot-tool/shot.mjs — chụp full-page, in kèm <meta robots>, console error và request lỗi (>=400):

cd /opt/screenshot-tool
node shot.mjs 'https://thegioikeycap.vn/keycap/' /đường/dẫn/ra.png 1440

Chạy node được ở BẤT KỲ đâu có node_modules — tức là phải chạy TỪ /opt/screenshot-tool, hoặc copy script sang đó trước, nếu không Cannot find package 'playwright'.

⚠️ Kiểm tra giao diện tĩnh (chụp ảnh) KHÔNG đủ cho nút bấm / form / JS. Bẫy đã sập thật: nút "Mua ngay" (xem docs/WP_THEME.md §3d) chỉ lộ ra khi bấm bằng trình duyệt thật — test bằng curl tự ghép payload tay đã báo đúng vì gõ tay đủ mọi tham số, thứ mà một cú click thật trên đúng nút đó không bao giờ tạo ra. Test nút bấm bằng Playwright thao tác thật (page.click()), không suy diễn từ request tự dựng:

// Chạy từ /opt/screenshot-tool: node ten-file.mjs
import { chromium } from 'playwright';
const browser = await chromium.launch();
const page = await (await browser.newContext({ viewport: { width: 1440, height: 900 } })).newPage();
await page.goto('https://thegioikeycap.vn/...', { waitUntil: 'networkidle' });
await page.locator('.selector-can-bam').click();
await page.waitForTimeout(2000);
console.log('URL sau khi bấm:', page.url());
await browser.close();

⚠️ Chromium headless mặc định bị should_track() coi là bot → trang trả về không có hàng đợi event, không có cookie _fbp. Muốn kiểm tra tracking phải set userAgent giả trình duyệt thật khi tạo context.


Đối chiếu tồn kho Woo ↔ Pancake

Chạy sau mỗi lần test đơn, và khi nghi ngờ lệch kho.

$WP eval '$o=[]; foreach(wc_get_products(["limit"=>-1,"return"=>"ids"]) as $i){
  $p=wc_get_product($i);
  foreach(($p->is_type("variable")?$p->get_children():[$i]) as $v){
    $x=wc_get_product($v); if($x) $o[strtoupper($x->get_sku())]=$x->get_stock_quantity(); }}
  echo json_encode($o);'

So với Pancake: GET /shops/{shop}/products/variations — đối chiếu display_id ↔ SKU và remain_quantity ↔ tồn Woo.

Hiện khớp 36/36 biến thể (chốt 06/09/2026).


Kiểm tra email

$WP eval 'var_dump( wp_mail("thegioikeycap+test@gmail.com","Test","Nội dung") );'
  • Trả false → cấu hình SMTP hỏng, không phải nội dung sai. Container không có MTA nên wp_mail() phụ thuộc hoàn toàn vào FluentSMTP.
  • Nhật ký gửi: WordPress admin → FluentSMTP → Email Logs.
  • ⚠️ Không bao giờ test bằng @example.com — hard bounce, hại uy tín tên miền.

Sao lưu

Script tự động: /srv/thegioikeycap.vn/docker/backup.sh (chạy hàng ngày qua cron lúc 20:00 UTC / 03:00 sáng VN, giữ 14 ngày).

# DB thủ công
/srv/thegioikeycap.vn/docker/backup.sh

# Code + uploads thủ công
tar czf /srv/backups/thegioikeycap.vn/tgk-www-$(date +%F).tar.gz -C /srv/thegioikeycap.vn www

Kho backup: /srv/backups/thegioikeycap.vn/.


Bảng tra nhanh khi có sự cố

Triệu chứng Nghi ngờ đầu tiên
Sửa code mà không thấy đổi OPcache 60 giây
Trang trắng, log trống Sai số tham số callback (ArgumentCountError)
Email không tới FluentSMTP / Brevo, không phải wp_mail()
Tồn kho lệch Đơn test dọn sai — hoàn kho hai lần
Pixel "không bắn" User-Agent bị coi là bot
Mô tả danh mục bị mất sau khi lưu Đoạn nới kses trong inc/category-content.php bị gỡ
Danh mục không vào sitemap Rank Math → Sitemap → Product Categories → Include Empty Terms
Đơn không sang POS send-app còn đang tắt sau lần test
Cước ship sai TGK_ALLINGO_MODE đang test → giá giả lập