From 2e4a11a7a0f8adde2a99273e9cef8b57b4aa4258 Mon Sep 17 00:00:00 2001 From: Aleksandar Grbic Date: Wed, 15 Jul 2026 11:07:15 +0200 Subject: [PATCH 1/2] =?UTF-8?q?perf(api):=20eslint=20--cache=20on=20lint/l?= =?UTF-8?q?int:fix=20(warm=20~23s=E2=86=92~2s,=20zero=20rule=20loss)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The UI already caches ESLint; the API did not, so every gate cycle paid ~23s per lint AND another ~23s when lint ran again in the check. Content-based cache invalidation, no rules changed. .eslintcache + *.tsbuildinfo gitignored. --- apps/api/.gitignore | 7 +++++++ apps/api/package.json | 4 ++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/apps/api/.gitignore b/apps/api/.gitignore index 7404e834..76fdfedc 100644 --- a/apps/api/.gitignore +++ b/apps/api/.gitignore @@ -10,6 +10,13 @@ /dist /build +# ESLint persistent cache — warm lint goes ~23s → ~2s (content-based +# invalidation, zero rule loss). Mirrors apps/ui. +.eslintcache + +# Incremental TypeScript build info (fast typecheck cache). +*.tsbuildinfo + # misc .DS_Store *.pem diff --git a/apps/api/package.json b/apps/api/package.json index 7b742f04..d28bf64b 100644 --- a/apps/api/package.json +++ b/apps/api/package.json @@ -24,8 +24,8 @@ "preview:templates": "bun run src/templates/email/preview.ts", "build": "bun run build:templates && bun build src/index.ts --outdir dist --target bun", "start": "bun run dist/index.js", - "lint": "eslint \"src/**/*.ts\" \"tests/**/*.ts\" \"scripts/**/*.ts\"", - "lint:fix": "eslint \"src/**/*.ts\" \"tests/**/*.ts\" \"scripts/**/*.ts\" --fix", + "lint": "eslint --cache \"src/**/*.ts\" \"tests/**/*.ts\" \"scripts/**/*.ts\"", + "lint:fix": "eslint --cache \"src/**/*.ts\" \"tests/**/*.ts\" \"scripts/**/*.ts\" --fix", "format": "prettier --write \"src/**/*.ts\" \"tests/**/*.ts\"", "typecheck": "tsc --noEmit", "knip": "knip", From 66ff0dbb958b704abe6eb04a306736e296c60834 Mon Sep 17 00:00:00 2001 From: Aleksandar Grbic Date: Wed, 15 Jul 2026 11:23:46 +0200 Subject: [PATCH 2/2] feat(scaffold): strip apps/docs from scaffolded products; make docs checks template-only MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit apps/docs is boringstack's OWN docs site — a scaffolded product must not carry or gate against it. Manifest declares strip:[apps/docs] for the full-stack archetype (tsforge deletes it post-clone). stack-check.sh now skips the docs checks (data + build:ci/og-image) when apps/docs is absent, so a product passes cleanly while the template itself (which keeps apps/docs) still checks it fully. --- .tsforge/scaffold-manifest.json | 3 ++- scripts/stack-check.sh | 18 +++++++++++++++--- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/.tsforge/scaffold-manifest.json b/.tsforge/scaffold-manifest.json index 3ed69fb4..d3916cf6 100644 --- a/.tsforge/scaffold-manifest.json +++ b/.tsforge/scaffold-manifest.json @@ -255,7 +255,8 @@ "healthUrls": [ "http://localhost:7331/", "http://localhost:7330/swagger/json" - ] + ], + "strip": ["apps/docs"] }, "astro": { "subPath": "apps/docs", diff --git a/scripts/stack-check.sh b/scripts/stack-check.sh index 42c60d66..6cf66039 100755 --- a/scripts/stack-check.sh +++ b/scripts/stack-check.sh @@ -21,7 +21,15 @@ run_check() { require_dir "api" "$BORINGSTACK_API_DIR" require_dir "ui" "$BORINGSTACK_UI_DIR" -require_dir "docs" "$BORINGSTACK_DOCS_DIR" + +# `docs` is TEMPLATE-ONLY. The boringstack repo ships apps/docs (its own docs site) +# and checks it here; a product scaffolded FROM boringstack strips apps/docs (see +# .tsforge/scaffold-manifest.json `strip`), so its docs checks are skipped rather +# than hard-failing. Present ⇒ run them (the template); absent ⇒ this is a product. +HAS_DOCS=0 +if [[ -d "$BORINGSTACK_DOCS_DIR" ]]; then + HAS_DOCS=1 +fi run_check "ACL drift" bash -c "cd \"$BORINGSTACK_API_DIR\" && bun run generate:acl-types:check" run_check "api lint-meta docs" bash -c "cd \"$BORINGSTACK_API_DIR\" && bun run check:lint-meta-docs" @@ -36,12 +44,16 @@ fi run_check "ui lint-meta docs" bash -c "cd \"$BORINGSTACK_UI_DIR\" && bun run check:lint-meta-docs" run_check "ui scripts docs" bash -c "cd \"$BORINGSTACK_UI_DIR\" && bun run check:scripts-docs" -run_check "docs data" bash -c "cd \"$BORINGSTACK_DOCS_DIR\" && BORINGSTACK_API_DIR=\"$BORINGSTACK_API_DIR\" BORINGSTACK_UI_DIR=\"$BORINGSTACK_UI_DIR\" bun run check:docs-data" +if [[ "$HAS_DOCS" == "1" ]]; then + run_check "docs data" bash -c "cd \"$BORINGSTACK_DOCS_DIR\" && BORINGSTACK_API_DIR=\"$BORINGSTACK_API_DIR\" BORINGSTACK_UI_DIR=\"$BORINGSTACK_UI_DIR\" bun run check:docs-data" +fi if [[ "$FULL" == "--full" ]]; then run_check "api validate" bash -c "cd \"$BORINGSTACK_API_DIR\" && bun run validate" run_check "ui validate" bash -c "cd \"$BORINGSTACK_UI_DIR\" && bun run validate" - run_check "docs build:ci" bash -c "cd \"$BORINGSTACK_DOCS_DIR\" && BORINGSTACK_API_DIR=\"$BORINGSTACK_API_DIR\" BORINGSTACK_UI_DIR=\"$BORINGSTACK_UI_DIR\" bun run build:ci" + if [[ "$HAS_DOCS" == "1" ]]; then + run_check "docs build:ci" bash -c "cd \"$BORINGSTACK_DOCS_DIR\" && BORINGSTACK_API_DIR=\"$BORINGSTACK_API_DIR\" BORINGSTACK_UI_DIR=\"$BORINGSTACK_UI_DIR\" bun run build:ci" + fi fi printf '\n'