From 210da28ec4a686380660c65b42fbae86d01be7c2 Mon Sep 17 00:00:00 2001 From: "codepress-dev[bot]" <202219725+codepress-dev[bot]@users.noreply.github.com> Date: Thu, 6 Aug 2026 21:19:40 +0000 Subject: [PATCH] Bootstrap repository readiness artifacts Co-authored-by: dev@codepress.dev --- .claude/skills/pr-screenshot/SKILL.md | 139 ++++++++++++++++++ .claude/skills/start-app-server/SKILL.md | 103 +++++++++++++ .claude/skills/verify-local/SKILL.md | 179 +++++++++++++++++++++++ .codepress/start-app-server/recipe.json | 28 ++++ .dockerignore | 13 ++ Dockerfile | 25 ++++ Dockerfile.codepress | 27 ++++ 7 files changed, 514 insertions(+) create mode 100644 .claude/skills/pr-screenshot/SKILL.md create mode 100644 .claude/skills/start-app-server/SKILL.md create mode 100644 .claude/skills/verify-local/SKILL.md create mode 100644 .codepress/start-app-server/recipe.json create mode 100644 .dockerignore create mode 100644 Dockerfile create mode 100644 Dockerfile.codepress diff --git a/.claude/skills/pr-screenshot/SKILL.md b/.claude/skills/pr-screenshot/SKILL.md new file mode 100644 index 0000000..8e33257 --- /dev/null +++ b/.claude/skills/pr-screenshot/SKILL.md @@ -0,0 +1,139 @@ +--- +name: pr-screenshot +description: "Capture and attach frontend screenshots and videos to pull requests for django-react-intro. Auto-triggers when a PR changes the React frontend or its styles." +user_invocable: true +codepress_generated: true +--- + +# PR Screenshot — django-react-intro + +Capture useful visual evidence for pull requests that change the React frontend. The repository has one frontend at `web/`, built with Create React App 1.0.10 and Yarn 1, and one public route: `/`. + +## When to Trigger + +Run this skill when a PR changes files under: + +- `web/src/**/*.{js,jsx,css}` +- `web/public/**/*` +- `web/package.json` or `web/yarn.lock` when the dependency change affects visible UI + +Do not run it for backend-only changes under `server/`, documentation-only changes, or test-only changes with no visual impact. + +## What to Capture + +| Changed files | What to screenshot | URL | +| --- | --- | --- | +| `web/src/containers/home/**` | Home screen and welcome content | `/` | +| `web/src/containers/App/**` or `web/src/containers/router/**` | Routed application shell | `/` | +| `web/src/index.css` or `web/src/**/*.css` | The affected page with its surrounding layout | `/` | +| `web/public/**` | Home screen using the changed public asset | `/` | + +The page is public and has no authentication or API data dependency. The key ready-state selector is the heading `Welcome to React`; the page root uses `.Home` and the logo uses `.Home-logo`. + +## Dev Server + +### Docker capture (preferred in CodePress sessions) + +The repository root `Dockerfile` is a self-contained validation image for the `web` app. It installs the pinned Yarn dependencies inside the image and starts CRA on port 3000. + +```text +build_and_start_app_server( + workspaceDir=, + dockerfilePath="Dockerfile", + port=3000, + envVars={ + "HOST":"0.0.0.0", + "PORT":"3000", + "BROWSER":"none", + "DANGEROUSLY_DISABLE_HOST_CHECK":"true", + "CHOKIDAR_USEPOLLING":"true" + } +) + +take_app_server_screenshot( + containerId=, + path="/", + viewport={"width":1440,"height":1100}, + wait_ms=1000, + full_page=false +) + +stop_app_server(containerId=) +``` + +Assert that the screenshot contains the changed feature, not just a non-blank shell. For this app, wait for the `Welcome to React` heading or another stable selector introduced by the PR. + +### Local Playwright fallback + +From `web/`, install dependencies with the existing Yarn lockfile. If Playwright is not already a dev dependency, add it once and install Chromium: + +```bash +cd web +yarn install --frozen-lockfile +yarn add --dev @playwright/test +yarn exec playwright install chromium +``` + +Create `web/e2e/playwright.config.js` temporarily when no config exists: + +```js +const { defineConfig } = require('@playwright/test'); + +module.exports = defineConfig({ + testDir: './tests', + use: { baseURL: 'http://127.0.0.1:3000' }, + webServer: { + command: 'HOST=0.0.0.0 BROWSER=none DANGEROUSLY_DISABLE_HOST_CHECK=true yarn start', + port: 3000, + reuseExistingServer: true, + timeout: 60000, + }, +}); +``` + +## Capture Spec Template + +Create `web/e2e/tests/_pr-screenshot.spec.js` temporarily and remove it after the run: + +```js +const { test } = require('@playwright/test'); + +test('capture the changed home screen', async ({ page }) => { + await page.goto('/'); + await page.getByRole('heading', { name: 'Welcome to React' }).waitFor({ state: 'visible' }); + await page.locator('.Home').scrollIntoViewIfNeeded(); + await page.screenshot({ + path: '/tmp/pr-screenshots/pr-screenshot-home.png', + fullPage: false, + }); +}); +``` + +For a PR that changes an interaction, record a short video with Playwright's `video: 'on'` setting and perform the real interaction before waiting for its final-state selector. Keep captures under ten seconds and include the final state. + +## Running the Spec + +```bash +cd web +mkdir -p /tmp/pr-screenshots +yarn exec playwright test --config e2e/playwright.config.js e2e/tests/_pr-screenshot.spec.js --workers=1 +``` + +Check that each screenshot is larger than 10 KB and that the changed content is visible. Capture a 390x844 viewport as well when the PR changes responsive behavior. Capture the same route against the merge-base in a detached worktree for a before/after pair when practical; if the base cannot render, keep the valid after capture and note why. + +## Upload and Embed + +In CodePress cloud sessions, call `upload_pr_asset` for each PNG, GIF, or WebM and embed the returned permanent URL in the PR's `## Demo` section. Use a before/after table when both captures exist, and stamp the section with the captured commit SHA. + +For local fallback, upload assets to the repository's `pr-assets` GitHub release with `gh release upload`, using PR-number-prefixed filenames. Prefer a GIF plus a link to the original WebM for video evidence. + +## Cleanup + +Remove the temporary spec and config, delete `/tmp/pr-screenshots`, and stop any server started for the capture. Do not commit temporary Playwright specs, configs, screenshots, or videos. + +## Tips + +- Use viewport captures for bounded UI changes and include enough height to show the feature below the header. +- Capture `/` for any shared component, router, or global-style change because the app currently has only that route. +- No auth bypass or API mocking is needed for this repository. +- Skip screenshots for changes that cannot affect rendered output. diff --git a/.claude/skills/start-app-server/SKILL.md b/.claude/skills/start-app-server/SKILL.md new file mode 100644 index 0000000..e0aed68 --- /dev/null +++ b/.claude/skills/start-app-server/SKILL.md @@ -0,0 +1,103 @@ +--- +name: start-app-server +description: "Start the django-react-intro web app in a Docker container and validate it responds. Uses a pre-validated recipe with no discovery or guessing." +user_invocable: true +codepress_generated: true +--- + +# Start App Server — django-react-intro + +Fast-path startup for the repository's Create React App frontend. Discovery was completed on 2026-08-06T21:12:43Z. The recipe is at `.codepress/start-app-server/recipe.json`. + +This recipe targets the independently runnable `web/` frontend on port 3000. The repository also contains a separate legacy Django backend under `server/`, but no combined full-stack start command was present during bootstrap. + +## Tools + +Use these tools directly: + +- `build_and_start_app_server` to build the image and start the container +- `forward_app_request` to send HTTP requests into the container +- `get_app_server_logs` to inspect startup failures +- `stop_app_server` to clean up a container + +## Static Context + +- **Stack**: Create React App 1.0.10, React 15.6.1, Yarn 1.22.22, Node 18 +- **Dockerfile**: `Dockerfile.codepress` +- **Port**: 3000 +- **Validation**: `GET /` with status in `[200, 301, 302, 404]` +- **Services**: none +- **Required secrets**: none + +## Step 1: Drift Check + +Compare the current inputs with the recipe checksums: + +```bash +git hash-object Dockerfile.codepress +git hash-object web/package.json +``` + +The expected first 16 characters are `34367fcd930b90e4` and `e334e8cea064856b`. A mismatch is a warning that the recipe may need updating; continue to build and report the drift. + +## Step 2: Environment + +No vault secrets or companion services are required. Use these safe runtime values: + +```json +{ + "HOST": "0.0.0.0", + "PORT": "3000", + "BROWSER": "none", + "DANGEROUSLY_DISABLE_HOST_CHECK": "true", + "CHOKIDAR_USEPOLLING": "true" +} +``` + +## Step 3: Build and Start + +```text +build_and_start_app_server( + workspaceDir=, + port=3000, + dockerfilePath="Dockerfile.codepress", + name="web", + envVars={ + "HOST":"0.0.0.0", + "PORT":"3000", + "BROWSER":"none", + "DANGEROUSLY_DISABLE_HOST_CHECK":"true", + "CHOKIDAR_USEPOLLING":"true" + } +) +``` + +If retrying after a fix, pass `existingContainerId` with the previous container ID so it is replaced cleanly. + +## Step 4: Validate + +When the tool reports `health_check: "ready"`, call: + +```text +forward_app_request(containerId=, path="/", method="GET") +``` + +Accept status 200, 301, 302, or 404. If health times out, poll `/` for up to 12 rounds at 5-second intervals and inspect `get_app_server_logs` before diagnosing a failure. A response outside the allowed statuses, a crash, or exhausted polling is a failed start. + +## Step 5: Report + +Report the container ID, port 3000, the request form above, and `stop_app_server(containerId=)` for cleanup. Leave a successfully started container running unless the caller is performing verification or explicitly asks for teardown. + +## Known Fixes + +- The tracked `.codepress/dev-server/Dockerfile.web` is a Live Dev Server image and does not contain application source or dependencies; use `Dockerfile.codepress` for standalone validation. +- The old CRA toolchain needs Node 18 and Yarn 1.22.22. Dependencies are installed during the image build. +- The server binds to `0.0.0.0`, with the browser disabled and polling enabled for containerized development. + +## Repair on Failure + +Read the full tool error and `get_app_server_logs` output before changing anything. Fix all identified issues together, rebuild with the previous container ID, and update the recipe checksums if the Dockerfile or `web/package.json` changes. Do not put secrets in the recipe or Dockerfile. If three prior repairs are recorded in `recipe.json`, stop and request a fresh bootstrap instead of looping. + +## Cleanup + +Do not stop a successful container when the user only asked to start the app. Stop failed containers and containers used solely for verification with `stop_app_server`. diff --git a/.claude/skills/verify-local/SKILL.md b/.claude/skills/verify-local/SKILL.md new file mode 100644 index 0000000..fca41c7 --- /dev/null +++ b/.claude/skills/verify-local/SKILL.md @@ -0,0 +1,179 @@ +--- +name: verify-local +description: "Verify django-react-intro locally: start the web app in Docker via the bootstrapped recipe, run HTTP assertions, and post a verification report to an open PR." +user_invocable: true +codepress_generated: true +--- + +# Verify Local — django-react-intro + +Start the repository's containerized Create React App frontend and exercise a real HTTP contract against it. Post a report to the open PR when one exists. + +This skill delegates all server configuration to `.claude/skills/start-app-server/SKILL.md` and `.codepress/start-app-server/recipe.json`. The recipe targets `web/` on port 3000. The separate legacy Django service in `server/` is not started by this recipe because the repository has no canonical combined start command; Django authentication assertions are therefore outside this local contract. + +The standard is to test every changed behavior from a real trigger surface. Do not replace live requests with code inspection, mocks, or a health check alone. + +## Quick Reference + +| Field | Value | +| --- | --- | +| Server runtime | Docker via the generated start-app-server skill | +| Mode | Local development recipe | +| Health endpoint | `GET /` → status in `[200, 301, 302, 404]` | +| Auth flow | None for the web frontend; no frontend auth gate or API calls were found | +| Test account | Not applicable to the selected web recipe | +| Session cookie | Not applicable | + +## Step 0: Confirm the Recipe + +Read `.codepress/start-app-server/recipe.json`. If it is missing, invalid JSON, or does not have `schema_version` equal to `1`, tell the user to run the app-server bootstrap first and stop. Confirm that `.claude/skills/start-app-server/SKILL.md` also exists and is generated. + +## Step 1: Inventory the Diff and Write the Contract + +Determine the current branch diff: + +```bash +DEFAULT_BRANCH=$(git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's@^refs/remotes/origin/@@' || echo master) +git diff "$DEFAULT_BRANCH"...HEAD --stat +git log "$DEFAULT_BRANCH"..HEAD --oneline +gh pr view --json title,body 2>/dev/null +``` + +Write a Diff Trigger Inventory before executing requests. Include every changed observable surface with `Surface`, `Location`, and `Contract item` columns. For this repository, frontend changes under `web/src/`, `web/public/`, or the frontend manifest map to the rendered `/` page; backend changes under `server/` are not covered by this recipe and must be reported as incomplete rather than silently omitted. + +Start with this default contract and add branch-specific rows for every changed behavior: + +| # | Method | Path | Expected | Notes | +| --- | --- | --- | --- | --- | +| 1 | GET | `/` | 200, 301, 302, or 404 | Container liveness and CRA HTML shell | +| 2 | GET | `/static/js/bundle.js` | 200 | Frontend JavaScript bundle is reachable | +| 3 | GET | `/manifest.json` | 200 | Public frontend asset is served | + +Do not invent a 404 assertion for this app: CRA's development server may return the application shell for unknown paths. Add a negative assertion only when the changed server surface has a grounded expected response. + +## Step 2: Start the App Server + +If the caller provides an `environment_artifact_path`, reuse it only when its recorded head SHA matches the current head and its health check still passes. Otherwise delegate to the generated fast path: + +```text +Skill({"skill": "start-app-server"}) +``` + +Capture the returned container ID as `CONTAINER_ID`. Write or update `/tmp/codepress-qa-verifier-runs/verify-env---.json` with the mode, current head SHA, diff range, container ID, base URL, ownership, health check, reuse instructions, and teardown command `stop_app_server(containerId=CONTAINER_ID)`. + +If startup fails, do not hand-start a server or mock it. Report the complete start failure and stop. + +## Step 3: Authentication + +The selected web container has no authentication gate and no frontend login flow. Skip login. Do not treat the Django `rest_auth` routes as covered because the Django service is not running in this recipe and no frontend code calls them. + +## Step 4: Execute the Contract + +Run every contract item in order with `forward_app_request` against the live container. Use real responses and record: + +- the actual HTTP status; +- the response body, or a concise excerpt when it is long; +- `✅ PASS` with a one-sentence confirmation, or `❌ FAIL` with a diagnosis. + +If a prerequisite fails, make up to three materially different recovery attempts, such as checking the exact route, reviewing container logs, and correcting a recipe or fixture issue. Do not mock around missing setup. Overall verification is `✅ PASS` only when every gap-worthy inventory row has a live passing result. + +## Step 5: UI Verification + +If the diff touches `web/src/**/*.{js,jsx,css}` or `web/public/**/*`, verify the rendered page at `/` with the browser. The page is ready when the `Welcome to React` heading or the changed feature's stable selector is visible, the page is not blank, and there are no uncaught console errors. + +If `.claude/skills/frontend-qa/SKILL.md` exists, invoke it for behavioral UI evidence and include its report and artifact manifest. If it does not exist, capture the changed page with: + +```text +take_app_server_screenshot( + containerId=CONTAINER_ID, + path="/", + viewport={"width":1280,"height":800}, + wait_ms=1000, + full_page=false +) +``` + +A screenshot is supporting evidence only; it cannot replace a behavior-specific contract assertion. Use `useCookieJar=true` only when a future frontend auth flow is added. + +## Step 6: Review Logs + +Always inspect the container logs after the contract: + +```text +get_app_server_logs(containerId=CONTAINER_ID, tail=500) +``` + +Record any error or stack trace related to the changed behavior. A clean response does not erase a runtime error that occurred during the flow. + +## Step 7: Write the Report + +Write `/tmp/local-verification-report.md`. Its first line must be exactly: + +```text +@codepress /judge-verification can you judge this verification? +``` + +Use this structure: + +```markdown +@codepress /judge-verification can you judge this verification? + +## Local Verification — django-react-intro + +**PR Head SHA:** `` + + + +**Environment artifact:** `/tmp/codepress-qa-verifier-runs/verify-env---.json` + +### Diff Trigger Inventory + +| Surface | Location | Contract item | +| --- | --- | --- | +| | | | + +### Verification Contract Results + +| # | Assertion | Result | Details | +| --- | --- | --- | --- | +| 1 | GET / → expected status | ✅ PASS | | + +### Frontend QA + +- Status: PASS / FAIL / not applicable +- Report: +- Manifest: +- Artifacts: + +### Log Review + +- + +### Container + +- ID: +- Stopped: yes / no + +### Overall: ✅ PASS +``` + +Replace the overall line with `### Overall: ❌ FAIL` if any contract row fails or if a changed backend behavior is outside this app-server surface. Keep the current live head SHA in both the prose field and the hidden marker. + +## Step 8: Post the Report + +If the current branch has an open PR, post the report with `post_pr_comment` using `repoDir` and the PR number. Confirm the report names the live PR head and contains the matching `codepress-verify-result` marker. If no PR exists, keep the report at the path above and include it in the session result. + +## Step 9: Cleanup + +When no PR needs the environment, or after the report is final, stop the container: + +```text +stop_app_server(containerId=CONTAINER_ID) +``` + +If a PR exists and a downstream judge will reuse the environment, leave teardown to the orchestrator. + +## Known Issues at Bootstrap Time + +- The local recipe validates only the React frontend. The Django backend has old dependencies, no canonical combined start command, and a broken WSGI module target; it is intentionally outside this generated contract. +- No frontend test account, auth fixture, or API mock is needed for the current public Home screen. diff --git a/.codepress/start-app-server/recipe.json b/.codepress/start-app-server/recipe.json new file mode 100644 index 0000000..a8c1d59 --- /dev/null +++ b/.codepress/start-app-server/recipe.json @@ -0,0 +1,28 @@ +{ + "schema_version": 1, + "bootstrapped_at": "2026-08-06T21:12:43Z", + "origin": "bootstrap", + "repair_count": 0, + "dockerfile_path": "Dockerfile.codepress", + "port": 3000, + "app_name": "web", + "validation_path": "/", + "validation_status_codes": [200, 301, 302, 404], + "static_env_vars": { + "HOST": "0.0.0.0", + "PORT": "3000", + "BROWSER": "none", + "DANGEROUSLY_DISABLE_HOST_CHECK": "true", + "CHOKIDAR_USEPOLLING": "true" + }, + "input_checksums": { + "dockerfile": "34367fcd930b90e4", + "dependency_manifest": "e334e8cea064856b" + }, + "system_packages": ["procps"], + "known_fixes": [ + "The existing .codepress/dev-server/Dockerfile.web is a thin Live Dev Server image without source or dependency installation; generated a self-contained Dockerfile.codepress for the web frontend.", + "Pinned the legacy CRA toolchain to Node 18 with Yarn 1.22.22 and installed dependencies during the image build." + ], + "discovery_notes": "This repository contains a legacy Create React App frontend in web/ and a separate Django 1.11 backend in server/. The durable app-server recipe targets the existing, independently runnable web frontend on port 3000; the Django service has no canonical combined start command, has no built frontend assets, and is not part of this single-server recipe." +} diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..e24ddd3 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,13 @@ +.git +.github +.claude +.agents +.codex +node_modules +web/node_modules +web/build +server/.venv +server/__pycache__ +server/*/__pycache__ +server/db.sqlite3 +*.log diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..f3306b7 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,25 @@ +# Generated by CodePress bootstrap-pr-screenshot for frontend validation. + +FROM public.ecr.aws/docker/library/node:18-bookworm + +RUN apt-get update \ + && apt-get install -y --no-install-recommends procps \ + && rm -rf /var/lib/apt/lists/* + +RUN corepack enable && corepack prepare yarn@1.22.22 --activate + +WORKDIR /app/web + +COPY web/package.json web/yarn.lock ./ +RUN yarn install --frozen-lockfile + +COPY web/ ./ + +ENV HOST=0.0.0.0 \ + PORT=3000 \ + BROWSER=none \ + DANGEROUSLY_DISABLE_HOST_CHECK=true + +EXPOSE 3000 + +CMD ["node", "node_modules/react-scripts/scripts/start.js"] diff --git a/Dockerfile.codepress b/Dockerfile.codepress new file mode 100644 index 0000000..34367fc --- /dev/null +++ b/Dockerfile.codepress @@ -0,0 +1,27 @@ +# Generated by CodePress bootstrap-app-server. +# Edits are preserved, but running /codepress-bootstrap-app-server again may overwrite them. + +FROM public.ecr.aws/docker/library/node:18-bookworm + +RUN apt-get update \ + && apt-get install -y --no-install-recommends procps \ + && rm -rf /var/lib/apt/lists/* + +RUN corepack enable && corepack prepare yarn@1.22.22 --activate + +WORKDIR /app/web + +COPY web/package.json web/yarn.lock ./ +RUN yarn install --frozen-lockfile + +COPY web/ ./ + +ENV HOST=0.0.0.0 \ + PORT=3000 \ + BROWSER=none \ + DANGEROUSLY_DISABLE_HOST_CHECK=true \ + CHOKIDAR_USEPOLLING=true + +EXPOSE 3000 + +CMD ["node", "node_modules/react-scripts/scripts/start.js"]