chore: add production smoke checks and execution directive
This commit is contained in:
@@ -1,5 +1,12 @@
|
|||||||
# Roadmap
|
# Roadmap
|
||||||
|
|
||||||
|
## Codex Execution Directive
|
||||||
|
|
||||||
|
- Highest-priority directive: continue driving this project toward production readiness without waiting for step-by-step confirmation.
|
||||||
|
- After each completed change, immediately proceed to the next highest-impact production issue unless the user explicitly pauses or redirects the work.
|
||||||
|
- Prioritize uptime, admin usability, content correctness, multilingual integrity, redirects, and frontend polish before lower-priority refactors.
|
||||||
|
- Keep the local git history current with meaningful commits as major stabilization steps land.
|
||||||
|
|
||||||
## Phase 0 — Discovery (current)
|
## Phase 0 — Discovery (current)
|
||||||
- Confirm brand positioning statement
|
- Confirm brand positioning statement
|
||||||
- Confirm CMS selection
|
- Confirm CMS selection
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
"devsafe": "rm -rf .next-dev && NEXT_DIST_DIR=.next-dev next dev",
|
"devsafe": "rm -rf .next-dev && NEXT_DIST_DIR=.next-dev next dev",
|
||||||
"build": "next build && node ./src/scripts/fix-next-main-app.mjs",
|
"build": "next build && node ./src/scripts/fix-next-main-app.mjs",
|
||||||
"start": "next start",
|
"start": "next start",
|
||||||
|
"smoke": "node ./src/scripts/smoke-check.mjs",
|
||||||
"lint": "next lint",
|
"lint": "next lint",
|
||||||
"generate:types": "payload generate:types",
|
"generate:types": "payload generate:types",
|
||||||
"payload": "payload",
|
"payload": "payload",
|
||||||
|
|||||||
@@ -0,0 +1,50 @@
|
|||||||
|
const base = process.argv[2] || process.env.SMOKE_BASE_URL || 'http://localhost:3070'
|
||||||
|
|
||||||
|
const routes = [
|
||||||
|
'/admin',
|
||||||
|
'/en',
|
||||||
|
'/zh',
|
||||||
|
'/en/products',
|
||||||
|
'/zh/products',
|
||||||
|
'/en/downloads',
|
||||||
|
'/zh/downloads',
|
||||||
|
'/en/news',
|
||||||
|
'/zh/news',
|
||||||
|
'/en/about',
|
||||||
|
'/zh/about',
|
||||||
|
'/en/support/contact',
|
||||||
|
'/zh/support/contact',
|
||||||
|
'/favicon.ico',
|
||||||
|
'/Product/index/model/DAC-Z10/target/X4C68nRijzjeq7k9e%5Bld%5D3ulg%3D%3D.html',
|
||||||
|
]
|
||||||
|
|
||||||
|
async function check(route) {
|
||||||
|
const url = new URL(route, base).toString()
|
||||||
|
const response = await fetch(url, { redirect: 'manual' })
|
||||||
|
const location = response.headers.get('location')
|
||||||
|
|
||||||
|
return {
|
||||||
|
route,
|
||||||
|
status: response.status,
|
||||||
|
location,
|
||||||
|
ok:
|
||||||
|
response.status === 200 ||
|
||||||
|
(route.includes('/Product/index/model/') && response.status === 301 && Boolean(location)) ||
|
||||||
|
(route === '/' && response.status === 307 && Boolean(location)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const results = await Promise.all(routes.map((route) => check(route)))
|
||||||
|
|
||||||
|
for (const result of results) {
|
||||||
|
const suffix = result.location ? ` -> ${result.location}` : ''
|
||||||
|
console.log(`${result.ok ? 'OK ' : 'BAD'} ${String(result.status).padEnd(3)} ${result.route}${suffix}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
const failures = results.filter((result) => !result.ok)
|
||||||
|
if (failures.length) {
|
||||||
|
console.error(`\nSmoke check failed for ${failures.length} route(s).`)
|
||||||
|
process.exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`\nSmoke check passed for ${results.length} route(s) against ${base}`)
|
||||||
Reference in New Issue
Block a user