From 395a88be160357fe2bf36aa7ed73bba04ca2bee6 Mon Sep 17 00:00:00 2001 From: Vishu Bhatnagar Date: Thu, 22 Oct 2026 14:22:31 +0100 Subject: [PATCH] chore: clarify web UI CI workflows and npm scripts Signed-off-by: Vishu Bhatnagar --- .../{server-lint-test.yml => bff-checks.yml} | 26 +++--- .../{client-generate.yml => client-build.yml} | 23 +++-- .github/workflows/client-e2e.yml | 28 +++---- .github/workflows/docker-release.yml | 24 +++--- ...lient-lint-test.yml => quality-checks.yml} | 28 +++---- .github/workflows/tls-smoke.yml | 18 ++-- .gitignore | 2 +- Dockerfile | 5 +- README.md | 84 +++++++++++-------- docs/DOCKER.md | 4 +- docs/RELEASE.md | 2 +- e2e/README.md | 5 +- package.json | 11 +-- scripts/refresh-openapi.sh | 2 +- server/package.json | 6 +- 15 files changed, 143 insertions(+), 125 deletions(-) rename .github/workflows/{server-lint-test.yml => bff-checks.yml} (69%) rename .github/workflows/{client-generate.yml => client-build.yml} (76%) rename .github/workflows/{client-lint-test.yml => quality-checks.yml} (64%) diff --git a/.github/workflows/server-lint-test.yml b/.github/workflows/bff-checks.yml similarity index 69% rename from .github/workflows/server-lint-test.yml rename to .github/workflows/bff-checks.yml index b9918c14..9f289a13 100644 --- a/.github/workflows/server-lint-test.yml +++ b/.github/workflows/bff-checks.yml @@ -1,17 +1,17 @@ # =============================================================== -# ๐Ÿงฉ Server Lint & Test - BFF Quality Gate +# ๐Ÿงฉ BFF Typecheck & Unit Tests # =============================================================== # - runs typecheck and Vitest for the BFF (server/) # - runs on PRs and pushes to main # --------------------------------------------------------------- -name: Server Lint & Test +name: BFF Typecheck & Unit Tests on: push: branches: ["main"] pull_request: - types: [opened, synchronize, ready_for_review] + types: [opened, synchronize, reopened, ready_for_review] branches: ["main"] concurrency: @@ -22,9 +22,9 @@ permissions: contents: read jobs: - lint-and-test: + typecheck-and-test: if: github.event_name != 'pull_request' || !github.event.pull_request.draft - name: Lint & Test Server + name: BFF typecheck and unit tests runs-on: ubuntu-latest timeout-minutes: 20 defaults: @@ -32,22 +32,22 @@ jobs: working-directory: server steps: - - name: โฌ‡๏ธ Checkout source + - name: Checkout source uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5 with: persist-credentials: false fetch-depth: 1 - - name: ๐ŸŸฉ Setup Node + - name: Setup Node uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 with: - node-version: "22" + node-version-file: ".nvmrc" - - name: ๐Ÿ“ฅ Install dependencies + - name: Install dependencies run: npm ci --no-audit --no-fund - - name: ๐Ÿ” Typecheck - run: npm run lint + - name: Typecheck + run: npm run typecheck - - name: ๐Ÿงช Run tests with Vitest - run: npm run test:run + - name: Run tests with Vitest + run: npm test diff --git a/.github/workflows/client-generate.yml b/.github/workflows/client-build.yml similarity index 76% rename from .github/workflows/client-generate.yml rename to .github/workflows/client-build.yml index d51ddcfc..a1ffb1b1 100644 --- a/.github/workflows/client-generate.yml +++ b/.github/workflows/client-build.yml @@ -1,13 +1,15 @@ # =============================================================== -# ๐Ÿงฌ Client Type Generation - verify generated types stay in sync +# ๐Ÿงฌ Client Build & Typecheck - validate generated API code # =============================================================== # - regenerates src/generated/ from the committed openapi.json # - verifies types exist, compile, and the app builds # --------------------------------------------------------------- -name: Client Type Generation +name: Client Build & Typecheck on: + push: + branches: ["main"] pull_request: branches: ["main"] types: [opened, synchronize, reopened, ready_for_review] @@ -21,14 +23,15 @@ concurrency: cancel-in-progress: true jobs: - generate-types: + build-client: if: github.event_name != 'pull_request' || !github.event.pull_request.draft - name: Generate, verify, and build types + name: Client build and typecheck runs-on: ubuntu-latest timeout-minutes: 20 steps: - - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5 + - name: Checkout source + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5 with: persist-credentials: false @@ -40,16 +43,10 @@ jobs: - name: Install dependencies run: npm ci --no-audit --no-fund - - name: Generate types with orval - run: npm run generate + - name: Generate API code, typecheck, and build client + run: npm run build - name: Verify generated types exist run: | test -d src/generated/types || (echo "ERROR: src/generated/types/ not created" && exit 1) echo "Generated types count: $(find src/generated/types -name '*.ts' | wc -l)" - - - name: Verify generated types compile - run: npx tsc -b --noEmit - - - name: Build - run: npm run build diff --git a/.github/workflows/client-e2e.yml b/.github/workflows/client-e2e.yml index 97b2486b..7ab2ac44 100644 --- a/.github/workflows/client-e2e.yml +++ b/.github/workflows/client-e2e.yml @@ -7,13 +7,13 @@ # - triggered on PRs and pushes to main # --------------------------------------------------------------- -name: Client E2E (Playwright) +name: Client E2E (Mocked API) on: push: branches: ["main"] pull_request: - types: [opened, synchronize, ready_for_review] + types: [opened, synchronize, reopened, ready_for_review] branches: ["main"] concurrency: @@ -26,7 +26,7 @@ permissions: jobs: playwright: if: github.event_name != 'pull_request' || !github.event.pull_request.draft - name: Playwright smoke + auth + name: Playwright mocked API tests runs-on: ubuntu-latest timeout-minutes: 30 @@ -35,24 +35,24 @@ jobs: PLAYWRIGHT_BROWSERS_PATH: ${{ github.workspace }}/.playwright-browsers steps: - - name: โฌ‡๏ธ Checkout source + - name: Checkout source uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5 with: persist-credentials: false fetch-depth: 1 - - name: ๐ŸŸฉ Setup Node + - name: Setup Node uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 with: node-version-file: ".nvmrc" - - name: ๐Ÿ“ฅ Install dependencies + - name: Install dependencies run: npm ci --no-audit --no-fund - - name: โš™๏ธ Generate types with orval - run: npm run generate + - name: Generate API code + run: npm run api:generate - - name: ๐ŸŽญ Cache Playwright browsers + - name: Cache Playwright browsers id: playwright-cache uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 with: @@ -61,18 +61,18 @@ jobs: restore-keys: | ${{ runner.os }}-playwright- - - name: ๐ŸŽญ Install Playwright browsers + - name: Install Playwright browsers if: steps.playwright-cache.outputs.cache-hit != 'true' run: npx playwright install --with-deps chromium - - name: ๐ŸŽญ Install Playwright system deps (cached browsers) + - name: Install Playwright system deps (cached browsers) if: steps.playwright-cache.outputs.cache-hit == 'true' run: npx playwright install-deps chromium - - name: ๐Ÿงช Run Playwright tests + - name: Run Playwright tests run: npm run e2e - - name: ๐Ÿ“ฆ Upload Playwright HTML report + - name: Upload Playwright HTML report if: always() uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: @@ -81,7 +81,7 @@ jobs: retention-days: 7 if-no-files-found: ignore - - name: ๐Ÿ“ฆ Upload Playwright traces on failure + - name: Upload Playwright traces on failure if: failure() uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: diff --git a/.github/workflows/docker-release.yml b/.github/workflows/docker-release.yml index fa251afc..37bfabe9 100644 --- a/.github/workflows/docker-release.yml +++ b/.github/workflows/docker-release.yml @@ -49,30 +49,30 @@ jobs: id-token: write # Cosign keyless (OIDC) signing steps: - - name: โฌ‡๏ธ Checkout source + - name: Checkout source uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5 with: persist-credentials: false - - name: ๐Ÿ”ก Set image name lowercase + - name: Set image name lowercase run: | IMAGE_NAME_LC=$(echo "${{ env.IMAGE_NAME }}" | tr '[:upper:]' '[:lower:]') echo "IMAGE_NAME_LC=${IMAGE_NAME_LC}" >> "${GITHUB_ENV}" - - name: ๐Ÿงฐ Set up QEMU (arm64 emulation) + - name: Set up QEMU (arm64 emulation) uses: docker/setup-qemu-action@96fe6ef7f33517b61c61be40b68a1882f3264fb8 # v4.2.0 - - name: ๐Ÿงฐ Set up Docker Buildx + - name: Set up Docker Buildx uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4.2.0 - - name: ๐Ÿ” Log in to GHCR + - name: Log in to GHCR uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - - name: ๐Ÿท๏ธ Extract image metadata + - name: Extract image metadata id: meta uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6.2.0 with: @@ -84,7 +84,7 @@ jobs: type=semver,pattern={{version}} type=semver,pattern={{major}}.{{minor}} - - name: โœ… Validate derived tags + - name: Validate derived tags run: | set -euo pipefail if [ -z "${{ steps.meta.outputs.tags }}" ]; then @@ -92,7 +92,7 @@ jobs: exit 1 fi - - name: ๐Ÿ—๏ธ Build & push image + - name: Build & push image id: build uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.3.0 with: @@ -112,10 +112,10 @@ jobs: build-args: | ${{ github.event.inputs.nodejs_image && format('NODEJS_IMAGE={0}', github.event.inputs.nodejs_image) || '' }} - - name: ๐Ÿ” Install Cosign + - name: Install Cosign uses: sigstore/cosign-installer@6f9f17788090df1f26f669e9d70d6ae9567deba6 # v4.1.2 - - name: ๐Ÿ” Sign published tags (keyless OIDC) + - name: Sign published tags (keyless OIDC) env: COSIGN_EXPERIMENTAL: "1" run: | @@ -125,14 +125,14 @@ jobs: echo "Signing ${IMAGE}@${DIGEST}" cosign sign --yes "${IMAGE}@${DIGEST}" - - name: ๐Ÿ“‹ Generate SBOM + - name: Generate SBOM uses: anchore/sbom-action@e22c389904149dbc22b58101806040fa8d37a610 # v0.24.0 with: image: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME_LC }}@${{ steps.build.outputs.digest }} output-file: sbom.spdx.json upload-artifact: false - - name: ๐Ÿ“ฆ Create GitHub Release + - name: Create GitHub Release uses: softprops/action-gh-release@3d0d9888cb7fd7b750713d6e236d1fcb99157228 # v3.0.2 with: tag_name: ${{ github.ref_name }} diff --git a/.github/workflows/client-lint-test.yml b/.github/workflows/quality-checks.yml similarity index 64% rename from .github/workflows/client-lint-test.yml rename to .github/workflows/quality-checks.yml index 7c633405..c92e3227 100644 --- a/.github/workflows/client-lint-test.yml +++ b/.github/workflows/quality-checks.yml @@ -1,18 +1,18 @@ # =============================================================== -# โš›๏ธ Client Lint & Test - React Frontend Quality Gate +# โš›๏ธ Repository Quality & Client Unit Tests # =============================================================== -# - runs ESLint, Prettier, and Vitest for the React client +# - runs repository-wide ESLint and Prettier, plus client Vitest coverage # - ensures code quality and test coverage for frontend # - runs on PRs and pushes to main # --------------------------------------------------------------- -name: Client Lint & Test +name: Repository Quality & Client Unit Tests on: push: branches: ["main"] pull_request: - types: [opened, synchronize, ready_for_review] + types: [opened, synchronize, reopened, ready_for_review] branches: ["main"] concurrency: @@ -23,35 +23,35 @@ permissions: contents: read jobs: - lint-and-test: + quality-and-client-tests: if: github.event_name != 'pull_request' || !github.event.pull_request.draft - name: Lint & Test Client + name: Repository quality and client unit tests runs-on: ubuntu-latest timeout-minutes: 20 steps: - - name: โฌ‡๏ธ Checkout source + - name: Checkout source uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5 with: persist-credentials: false fetch-depth: 1 - - name: ๐ŸŸฉ Setup Node + - name: Setup Node uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 with: node-version-file: ".nvmrc" - - name: ๐Ÿ“ฅ Install dependencies + - name: Install dependencies run: npm ci --no-audit --no-fund - - name: โš™๏ธ Generate types with orval - run: npm run generate + - name: Generate API code + run: npm run api:generate - - name: ๐ŸŽจ Check code formatting with Prettier + - name: Check code formatting with Prettier run: npm run format:check - - name: ๐Ÿ” Lint code with ESLint + - name: Lint code with ESLint run: npm run lint - - name: ๐Ÿงช Run tests with Vitest + - name: Run tests with Vitest run: npm run test:coverage diff --git a/.github/workflows/tls-smoke.yml b/.github/workflows/tls-smoke.yml index 5bc755e0..71b66c12 100644 --- a/.github/workflows/tls-smoke.yml +++ b/.github/workflows/tls-smoke.yml @@ -24,7 +24,7 @@ on: - "server/src/config.ts" - ".github/workflows/tls-smoke.yml" pull_request: - types: [opened, synchronize, ready_for_review] + types: [opened, synchronize, reopened, ready_for_review] branches: ["main"] paths: - "infra/nginx/**" @@ -58,39 +58,39 @@ jobs: NGINX_FORCE_HTTPS: "true" steps: - - name: โฌ‡๏ธ Checkout source + - name: Checkout source uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5 with: persist-credentials: false fetch-depth: 1 - - name: ๐ŸŸฉ Setup Node + - name: Setup Node uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 with: node-version-file: ".nvmrc" - - name: ๐Ÿ“„ Prepare .env + - name: Prepare .env run: cp .env.example .env - - name: ๐Ÿณ Bring up the TLS e2e stack + - name: Bring up the TLS e2e stack run: npm run e2e:docker:tls:up - - name: ๐ŸŒฑ Seed test user + - name: Seed test user run: npm run e2e:docker:seed env: E2E_GATEWAY_URL: https://localhost:4444 NODE_EXTRA_CA_CERTS: ${{ github.workspace }}/certs/cert.pem - - name: ๐Ÿšฌ Run TLS smoke checks + - name: Run TLS smoke checks run: npm run tls:smoke env: SMOKE_EMAIL: ${{ env.E2E_TEST_EMAIL }} SMOKE_PASSWORD: ${{ env.E2E_TEST_PASSWORD }} - - name: ๐Ÿ“‹ Dump stack logs on failure + - name: Dump stack logs on failure if: failure() run: docker compose -f docker-compose.e2e.yml -f docker-compose.tls.yml -f docker-compose.e2e-tls.yml logs --no-color - - name: ๐Ÿงน Tear down the TLS e2e stack + - name: Tear down the TLS e2e stack if: always() run: npm run e2e:docker:tls:down diff --git a/.gitignore b/.gitignore index d9f8063f..94213993 100644 --- a/.gitignore +++ b/.gitignore @@ -25,7 +25,7 @@ server/.env !.env.example !server/.env.example -# Self-signed TLS certs (npm run certs / docker-compose.tls.yml) +# Self-signed TLS certs (npm run tls:certs / docker-compose.tls.yml) certs/ # Alternative package manager lock files diff --git a/Dockerfile b/Dockerfile index e5139088..cfa210c4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -24,8 +24,9 @@ COPY --chown=1001:0 package.json package-lock.json ./ RUN npm ci --no-audit --no-fund # ---- UI build ---- -# npm run build = "npm run generate && tsc -b && vite build". `generate` -# runs orval against the committed openapi.json (no network call). vite's +# npm run build generates API code, checks types, then runs vite build. +# api:generate runs orval against the committed openapi.json (no network +# call). Vite's # outDir is "server/public", so output lands at # /opt/app-root/src/server/public here. FROM ui-deps AS ui-build diff --git a/README.md b/README.md index 092ad0f0..064b36b1 100644 --- a/README.md +++ b/README.md @@ -162,10 +162,10 @@ npm run preview TypeScript types and fetch clients under `src/generated/` come from [`openapi.json`](./openapi.json) via [Orval](./orval.config.ts). That file is committed and pinned to API v1.1.0, not re-fetched at build time. ```bash -npm run generate # regenerate src/generated/ from ./openapi.json +npm run api:generate # regenerate src/generated/ from ./openapi.json ``` -To bump the API version, replace `openapi.json` with the new spec, update the version note above, then run `npm run generate`. +To bump the API version, replace `openapi.json` with the new spec, update the version note above, then run `npm run api:generate`. ## Code Quality @@ -232,10 +232,10 @@ The scan also runs automatically as a **pre-commit hook** (via Husky). ```bash # Run tests in watch mode -npm run test +npm run test:watch # Run tests once (CI mode) -npm run test:run +npm run test # Run tests with UI npm run test:ui @@ -244,6 +244,15 @@ npm run test:ui npm run test:coverage ``` +Both the root client package and `server/` use `npm test` for a single run and +`npm run test:watch` for watch mode. Root `npm run lint` runs ESLint across +`src/`, `server/`, and `e2e/`; `npm run format:check` checks formatting across +the configured root files and those directories. + +Use `npm run typecheck` for the client and Vite configuration, and +`npm run typecheck --prefix server` for the BFF. Generate client API code with +`npm run api:generate` before checking types on a clean checkout. + ### Test Structure ``` @@ -339,8 +348,10 @@ See [`e2e/README.md`](./e2e/README.md) for layout, fixtures, and guidelines. ### GitHub Actions -Tests and linting run automatically on pull requests via [`.github/workflows/client-lint-test.yml`](./.github/workflows/client-lint-test.yml). -E2E tests run via [`.github/workflows/client-e2e.yml`](./.github/workflows/client-e2e.yml). +Repository-wide formatting and ESLint checks, followed by client unit tests with coverage, run on pull requests via [`.github/workflows/quality-checks.yml`](./.github/workflows/quality-checks.yml). +Client builds and typechecking run via [`.github/workflows/client-build.yml`](./.github/workflows/client-build.yml). +BFF typechecking and unit tests run via [`.github/workflows/bff-checks.yml`](./.github/workflows/bff-checks.yml). +Mocked API E2E tests run via [`.github/workflows/client-e2e.yml`](./.github/workflows/client-e2e.yml). **Workflow Steps:** @@ -351,8 +362,12 @@ E2E tests run via [`.github/workflows/client-e2e.yml`](./.github/workflows/clien **Triggers:** -- Push to `main` or `epic/ui-rewrite` branches -- Pull requests to `main` or `epic/ui-rewrite` branches +- Pushes to `main` +- Non-draft pull requests targeting `main` (opened, updated, reopened, or marked ready for review) + +The TLS smoke workflow additionally filters by relevant file paths. Docker +releases run on version tags or manual dispatch; the client build also supports +manual dispatch. ## Project Structure @@ -400,30 +415,33 @@ Run from the repo root unless noted. Visit the app on the BFF's port (`:3000`) either way โ€” see [Getting Started](#getting-started) for the full dev setup. -| Script | Description | -| ---------------------------- | ------------------------------------------------------------------------------------------------- | -| `npm run dev` | Vite dev server (`:5173`) โ€” not visited directly; the BFF proxies to it for HMR | -| `npm run dev` (in `server/`) | **Start the BFF (`:3000`)** โ€” serves the SPA (or proxies to Vite) and proxies `/api/*` to the API | -| `npm run dev:all` | Both of the above together (via `concurrently`), `VITE_DEV_SERVER_URL` already set | -| `npm run build` | Build the SPA into `server/public/`, which the BFF serves directly (no Vite dev server) | -| `npm run build:watch` | Rebuild on change โ€” for iterating without HMR, against the BFF-served build | -| `npm run generate` | Regenerate API types from `openapi.json` | -| `npm run preview` | Preview production build | -| `npm run lint` | Check for linting errors | -| `npm run lint:fix` | Auto-fix linting errors | -| `npm run format` | Format all files with Prettier | -| `npm run format:check` | Check formatting without changes | -| `npm run test` | Run tests in watch mode | -| `npm run test:run` | Run tests once (CI mode) | -| `npm run test:ui` | Run tests with UI | -| `npm run test:coverage` | Generate coverage report | -| `npm run e2e` | Run Playwright E2E tests | -| `npm run e2e:ui` | Playwright UI mode | -| `npm run e2e:debug` | Playwright Inspector | -| `npm run e2e:install` | Install Playwright browsers | -| `npm run e2e:report` | Open last Playwright report | -| `npm run secrets:scan` | Scan repo for secrets, update `.secrets.baseline` | -| `npm run secrets:audit` | Interactively audit findings in `.secrets.baseline` | +| Script | Description | +| ----------------------------------- | ------------------------------------------------------------------------------------------------- | +| `npm run dev` | Vite dev server (`:5173`) โ€” not visited directly; the BFF proxies to it for HMR | +| `npm run dev` (in `server/`) | **Start the BFF (`:3000`)** โ€” serves the SPA (or proxies to Vite) and proxies `/api/*` to the API | +| `npm run dev:all` | Both of the above together (via `concurrently`), `VITE_DEV_SERVER_URL` already set | +| `npm run build` | Build the SPA into `server/public/`, which the BFF serves directly (no Vite dev server) | +| `npm run build:watch` | Rebuild on change โ€” for iterating without HMR, against the BFF-served build | +| `npm run api:generate` | Regenerate API types from `openapi.json` | +| `npm run preview` | Preview production build | +| `npm run typecheck` | Typecheck the client and Vite configuration | +| `npm run typecheck --prefix server` | Typecheck the BFF | +| `npm run tls:certs` | Generate local self-signed TLS certificates | +| `npm run lint` | Check for linting errors | +| `npm run lint:fix` | Auto-fix linting errors | +| `npm run format` | Format all files with Prettier | +| `npm run format:check` | Check formatting without changes | +| `npm run test:watch` | Run tests in watch mode | +| `npm run test` | Run tests once (CI mode) | +| `npm run test:ui` | Run tests with UI | +| `npm run test:coverage` | Generate coverage report | +| `npm run e2e` | Run Playwright E2E tests | +| `npm run e2e:ui` | Playwright UI mode | +| `npm run e2e:debug` | Playwright Inspector | +| `npm run e2e:install` | Install Playwright browsers | +| `npm run e2e:report` | Open last Playwright report | +| `npm run secrets:scan` | Scan repo for secrets, update `.secrets.baseline` | +| `npm run secrets:audit` | Interactively audit findings in `.secrets.baseline` | ## Internationalization (i18n) @@ -472,6 +490,6 @@ The test setup includes a mock for `window.matchMedia` in `src/test/setup.ts`. I 1. Follow the existing code style (enforced by ESLint and Prettier) 2. Write tests for new features -3. Ensure all tests pass: `npm run test:run` +3. Ensure all tests pass: `npm run test` 4. Ensure linting passes: `npm run lint` 5. Ensure formatting is correct: `npm run format:check` diff --git a/docs/DOCKER.md b/docs/DOCKER.md index 2d9e19b5..8a4c8b34 100644 --- a/docs/DOCKER.md +++ b/docs/DOCKER.md @@ -111,13 +111,13 @@ equivalent โ€” see [`sso-keycloak-setup.md`](./sso-keycloak-setup.md). ## Local TLS (self-signed certs) -`npm run certs` generates a self-signed cert/key pair for local HTTPS +`npm run tls:certs` generates a self-signed cert/key pair for local HTTPS testing, written to `./certs/cert.pem` and `./certs/key.pem` (gitignored, never committed). It's idempotent โ€” safe to re-run, and it refuses to overwrite a cert you've placed there yourself. ```bash -npm run certs +npm run tls:certs ``` The cert covers `localhost`, `127.0.0.1`, and the internal service names diff --git a/docs/RELEASE.md b/docs/RELEASE.md index 30f499bb..262fe1d2 100644 --- a/docs/RELEASE.md +++ b/docs/RELEASE.md @@ -20,7 +20,7 @@ This runs [`scripts/refresh-openapi.sh`](./scripts/refresh-openapi.sh), which: 1. Verifies the sibling checkout has a remote pointing at `IBM/mcp-context-forge`, then pulls `main` there (default location: `../mcp-context-forge`; override with `OPENAPI_SOURCE_DIR` or a path argument). 2. Regenerates `openapi.json` from it and pins `info.version` to `+` โ€” [semver build metadata](https://semver.org/#spec-item-10), no spaces or parentheses (e.g. `1.0.0+589c69`). 3. Updates the two places the README quotes that same pin (the `This UI targets **ContextForge API vX.Y.Z**` line and the codegen note further down). -4. Runs `npm run generate` to regenerate the API client. +4. Runs `npm run api:generate` to regenerate the API client. 5. Commits on a new `chore/openapi-...` branch (based on `origin/main`). Run with `--dry-run` to stop after step 4 and inspect `git diff` yourself before committing anything. Both the API checkout and this repo must have a clean working tree before you run it. diff --git a/e2e/README.md b/e2e/README.md index 083a269e..24bc3da7 100644 --- a/e2e/README.md +++ b/e2e/README.md @@ -127,8 +127,9 @@ Keep smoke tests: ## CI Runs in -[`.github/workflows/client-e2e.yml`](../../.github/workflows/client-e2e.yml) on -PRs and pushes to `main` / `epic/ui-rewrite` that touch `client/**`. +[`.github/workflows/client-e2e.yml`](../.github/workflows/client-e2e.yml) on +non-draft PRs targeting `main` and pushes to `main`. The suite uses mocked +API responses; real API Docker runs are available through the scripts above. ## Troubleshooting diff --git a/package.json b/package.json index 7f728bf7..7082b899 100644 --- a/package.json +++ b/package.json @@ -12,9 +12,11 @@ "dev:e2e": "vite --base=/ --port 5173 --strictPort", "predev:bff": "npm ls --prefix server --depth=0 >/dev/null 2>&1 || (echo 'Dependencies missing or out of date in server/ โ€” run: npm install --prefix server' >&2 && exit 1)", "dev:bff": "VITE_DEV_SERVER_URL=http://localhost:5173 npm run dev --prefix server", - "predev:all": "npm run predev --silent && ([ -f openapi.json ] || (echo 'openapi.json is missing at repo root โ€” generate reads from it and will fail with a less helpful error. Restore it (e.g. git checkout main -- openapi.json), see README.md#api-types' >&2 && exit 1)) && npm run generate", + "predev:all": "npm run predev --silent && ([ -f openapi.json ] || (echo 'openapi.json is missing at repo root โ€” api:generate reads from it and will fail with a less helpful error. Restore it (e.g. git checkout main -- openapi.json), see README.md#api-types' >&2 && exit 1)) && npm run api:generate", "dev:all": "concurrently -n BFF,WEB -c blue,green \"npm run dev:bff\" \"npm run dev\"", - "build": "npm run generate && tsc -b && vite build", + "api:generate": "orval", + "typecheck": "tsc -b --noEmit", + "build": "npm run api:generate && npm run typecheck && vite build", "build:watch": "vite build --watch", "preview": "vite preview", "lint": "eslint --no-error-on-unmatched-pattern src server e2e", @@ -25,7 +27,7 @@ "test:ui": "vitest --ui", "test:watch": "vitest", "test:coverage": "vitest run --coverage", - "e2e": "playwright test --reporter=list", + "e2e": "playwright test", "e2e:docker:up": "docker compose -f docker-compose.e2e.yml up -d --wait --build", "e2e:docker:seed": "node --env-file-if-exists=.env --experimental-strip-types e2e/seed/seed.ts", "e2e:docker:down": "docker compose -f docker-compose.e2e.yml down -v", @@ -40,9 +42,8 @@ "e2e:report": "playwright show-report", "i18n:extract": "formatjs extract 'src/**/*.{ts,tsx}' --out-file src/i18n/extracted.json --id-interpolation-pattern '[sha512:contenthash:base64:6]'", "i18n:compile": "formatjs compile-folder --ast src/i18n/locales src/i18n/compiled", - "generate": "orval", "openapi:refresh": "bash scripts/refresh-openapi.sh", - "certs": "sh scripts/gen-certs.sh", + "tls:certs": "sh scripts/gen-certs.sh", "compose:tls": "docker compose -f docker-compose.yml -f docker-compose.tls.yml up -d --wait --build", "compose:tls:down": "docker compose -f docker-compose.yml -f docker-compose.tls.yml down", "tls:smoke": "sh scripts/tls-smoke.sh", diff --git a/scripts/refresh-openapi.sh b/scripts/refresh-openapi.sh index 1ce73313..471bb131 100755 --- a/scripts/refresh-openapi.sh +++ b/scripts/refresh-openapi.sh @@ -159,7 +159,7 @@ write_changes() { [[ "$SPEC_CHANGED" == 1 ]] && cp "$TMP_SPEC" "$REPO_ROOT/openapi.json" [[ "$README_CHANGED" == 1 ]] && cp "$TMP_README" "$REPO_ROOT/README.md" echo "==> Regenerating API client" - (cd "$REPO_ROOT" && npm run generate) + (cd "$REPO_ROOT" && npm run api:generate) } if [[ "$DRY_RUN" == "1" ]]; then diff --git a/server/package.json b/server/package.json index c30375d3..ba4a5b7e 100644 --- a/server/package.json +++ b/server/package.json @@ -11,9 +11,9 @@ "dev": "tsx watch --env-file-if-exists=../.env src/index.ts", "build": "tsc -p tsconfig.json", "start": "node --env-file-if-exists=../.env dist/index.js", - "test": "vitest", - "test:run": "vitest run", - "lint": "tsc -p tsconfig.json --noEmit" + "test": "vitest run", + "typecheck": "tsc -p tsconfig.json --noEmit", + "test:watch": "vitest" }, "dependencies": { "@fastify/compress": "^9.2.0",