Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 94 additions & 0 deletions .claude/skills/pr-screenshot/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
---
name: pr-screenshot
description: "Capture frontend screenshots and videos for quantfive/django-react-intro pull requests. Auto-triggers when a PR diff changes visible files under web/src, web/public, or web/package.json. Uses Playwright to render the Create React App home page and uploads evidence to the PR. IMPORTANT: Use this skill whenever a PR includes frontend or UI changes. Trigger on: make a PR, create a PR, open a pull request, or any request that results in a PR with frontend file changes."
user_invocable: true
codepress_generated: true
---

# PR Screenshots — quantfive/django-react-intro

Capture useful visual evidence for UI changes in the `web/` Create React App. The current frontend has one renderable route, `/`, served by `react-scripts start` on port 3000. The Django code under `server/` is not a screenshot surface unless the frontend is changed to consume it.

## When to Trigger

Run this skill when the PR changes visible frontend behavior in:

- `web/src/**/*.{js,jsx,css,svg}`
- `web/public/**/*.{html,json,ico}`
- `web/package.json` or `web/e2e/**/*`

Do not run it for backend-only changes under `server/`, documentation-only changes, dependency updates with no visible effect, or test-only changes that do not alter the rendered UI.

## What to Capture

| Changed files | What to screenshot | URL |
| --- | --- | --- |
| `web/src/containers/home/**` | Home screen and its welcome content | `/` |
| `web/src/containers/App/**` | Application shell and routed home screen | `/` |
| `web/src/containers/router/**` | The route affected by the change | `/` |
| `web/src/index.css`, `web/src/containers/home/stylesheets/**` | Home screen styling | `/` |
| `web/public/**` | Home screen with updated public assets or metadata | `/` |

This is a static starter app with no discovered login flow, protected route, API fixture, or seeded account. Capture the public home screen without auth injection or API mocks. Use a screenshot for layout, typography, color, and asset changes. Add a video only when the diff introduces an interaction, animation, loading state, or drag-and-drop flow.

## Dev Server

The durable local capture path uses the `web/e2e/playwright.config.js` file committed with this skill. It starts the existing CRA app with:

```bash
cd web
yarn install --frozen-lockfile
yarn playwright install chromium
yarn playwright test --config=e2e/playwright.config.js
```

The server binds to `0.0.0.0:3000`, disables browser launching, and allows the CodePress preview hostname. In a CodePress cloud session, use the available container-backed browser or Live Dev Server flow when it provides the same frontend; otherwise use the Playwright config above. Do not use the existing `.codepress/dev-server/Dockerfile.web` with a standalone app-server build unless the source tree is explicitly mounted, because that image intentionally expects runtime dependency hydration from a bind-mounted checkout.

## Capture Spec

Create a temporary spec at `web/e2e/tests/_validate-pr-screenshot.spec.js` and remove it after the run:

```js
const { test, expect } = require('@playwright/test');

test('capture the public home screen for a pull request', async ({ page }) => {
await page.goto('/');
await expect(page.getByRole('heading', { name: 'Welcome to React' })).toBeVisible();
await expect(page.getByText(/To get started, edit/)).toBeVisible();
await page.screenshot({
path: '/tmp/pr-screenshots/pr-screenshot-home.png',
fullPage: false,
});
});
```

Run it from the repository root:

```bash
rm -rf /tmp/pr-screenshots
mkdir -p /tmp/pr-screenshots
cd web
yarn playwright test --config=e2e/playwright.config.js e2e/tests/_validate-pr-screenshot.spec.js --workers=1
test -s /tmp/pr-screenshots/pr-screenshot-home.png
rm -f e2e/tests/_validate-pr-screenshot.spec.js
```

The screenshot must contain the visible home content, not only a blank shell or loading state, and should be larger than 10 KB. If the PR changes the only heading or intro copy, update the semantic assertions in the temporary spec to match the changed final state while keeping an assertion that the changed content is visible.

## Before and After

For an existing route, capture the same spec on the merge-base in a temporary detached worktree and save the result with a `-before` suffix. The before pass is best effort: a dependency or fixture mismatch must fall back to the current-branch capture rather than invalidate the after screenshot. A new route has no before image.

Stamp the PR evidence with the short commit SHA so reviewers can identify stale screenshots after later commits.

## Video Capture

For interactive changes, enable Playwright video in the temporary spec with a 1280 by 720 viewport, perform the shortest readable interaction path, wait for the final state, and close the page so recording finalizes. Convert the resulting WebM to a GIF with `ffmpeg` for inline PR rendering, and retain the WebM as a download.

## Upload and Embed

In CodePress cloud sessions, upload each PNG, GIF, and WebM with `upload_pr_asset` and embed the returned permanent URLs in a `## Demo` section of the PR body. Use linked image markdown so clicking an image opens the full asset. For local sessions without that tool, upload the assets to the repository's `pr-assets` release with `gh release upload` and use the release URLs. Include before/after images in a two-column table when both exist; otherwise show the after image alone.

## Cleanup

Always remove the temporary spec, stop any server started solely for capture, and clear `/tmp/pr-screenshots` after assets are uploaded or copied. Do not commit screenshots, videos, temporary specs, or generated dependency directories.
110 changes: 110 additions & 0 deletions .claude/skills/start-app-server/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
---
name: start-app-server
description: "Start the quantfive/django-react-intro frontend in a Docker container and validate that it responds. Uses a pre-validated recipe with no discovery or guessing. Triggers on: spin up the server, run my app, start the server, verify app server, test my server, run app server, spin up the app."
user_invocable: true
codepress_generated: true
---

# Start App Server — quantfive/django-react-intro

Fast-path skill for starting the repository's app server. Discovery was completed on 2026-08-10T04:15:25Z. Read the recipe and execute it directly.

The recipe lives at `.codepress/start-app-server/recipe.json`.

## 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 running container
- `get_app_server_logs` to inspect container output
- `stop_app_server` to clean up when requested
- `list_vault_secrets` and `get_vault_secrets` only when a future recipe adds required secrets

## Static Context

- **Stack:** Create React App 1.0.10 under `web/`, served by the CRA development server
- **Dockerfile:** `Dockerfile`
- **Port:** 3000
- **Validation:** `GET /` with status in `[200, 301, 302, 404]`
- **Services:** none
- **Required secrets:** none

## Step 1: Drift Check

From the repository root, compare these hashes with `recipe.input_checksums`:

```bash
git hash-object Dockerfile
git hash-object web/package.json
```

The recorded values are:

- Dockerfile: `f62f4ad864b4fcbe`
- Dependency manifest: `3e3a3c381db1ac9e`

If either value differs, continue with the build but report that the recipe may need regeneration.

## Step 2: Build and Start

This app needs no vault secrets or static environment overrides.

```text
build_and_start_app_server(
workspaceDir=<absolute path to the repository root>,
port=3000,
dockerfilePath="Dockerfile",
envVars={}
)
```

The Dockerfile installs Yarn 1.22.22 and all frontend dependencies during image build, then runs the installed CRA binary directly. The server binds to `0.0.0.0:3000`.

If retrying after a Dockerfile or dependency fix, pass `existingContainerId=<previous id>` so the prior container is stopped after a successful rebuild.

## Step 3: Validate

If the start tool reports that the container is ready, send a real request:

```text
forward_app_request(
containerId=CONTAINER_ID,
path="/",
method="GET"
)
```

A response with status 200, 301, 302, or 404 confirms that the server is reachable. If startup times out, poll the same path up to 12 times at five-second intervals and inspect `get_app_server_logs` before deciding that the container failed.

## Step 4: Report

Tell the user:

- Container ID
- Port 3000
- How to call `forward_app_request(containerId=..., path="/")`
- How to stop it with `stop_app_server(containerId=...)`

If the user only asked to start the server, stop after reporting the live container. Leave a successful container running for the caller.

## Known Fixes

- The existing `.codepress/dev-server/Dockerfile.web` is a bind-mount-only Live Dev Server image, so this recipe uses a standalone root Dockerfile.
- `@playwright/test` is pinned to 1.53.2 because newer releases require Node 20 and the CRA image uses Node 18.

## Repair on Failure

If the build or start fails:

1. Read the complete tool error and `get_app_server_logs` output.
2. Check the Dockerfile and `web/package.json` together for dependency or port drift.
3. Fix all identified issues before rebuilding.
4. Retry with `existingContainerId` when a prior container exists.
5. After three prior repairs, stop and request a fresh bootstrap rather than looping.

Only update the recipe after a real repair: set `origin` to `repair`, increment `repair_count`, refresh `bootstrapped_at` and input hashes, and append a short entry to `known_fixes`.

## Cleanup

Do not stop a successfully started container unless the user asks for teardown or it was started only for a validation run that is now complete. Stop failed containers so they do not leak.
163 changes: 163 additions & 0 deletions .claude/skills/verify-local/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
---
name: verify-local
description: "Verify quantfive/django-react-intro locally: start the web frontend in Docker via the bootstrapped recipe and run a public HTTP contract. Triggers on: verify locally, local verify, local validation, test locally, run checks."
user_invocable: true
codepress_generated: true
---

# Verify Local — quantfive/django-react-intro

Start the repository's selected app-server surface in Docker, exercise every relevant HTTP trigger for the current diff, inspect the logs, and write a verification report. The current recipe covers the public Create React App frontend under `web/` on port 3000. It does not start or verify the separate Django source under `server/`; changes that require the Django process are outside this recipe and must not be silently reported as verified.

This skill delegates startup to `.claude/skills/start-app-server/SKILL.md`, so Dockerfile, port, and environment configuration stay in one place. Verification only counts when requests reach the real container through `forward_app_request`; do not replace the app with mocks.

## Quick Reference

| Field | Value |
| --- | --- |
| Server runtime | Docker via the start-app-server recipe |
| Mode | Development CRA server |
| Health endpoint | `GET /` → status in `[200, 301, 302, 404]` |
| Auth flow | None on the selected web surface; the separate Django auth routes are not served by this recipe |
| Test account | None required or discovered |
| Cookie session | Use `useCookieJar: true` on contract requests for consistent proxy behavior |

## Step 0: Confirm the Recipe

Read `.codepress/start-app-server/recipe.json`. If it is missing, invalid, or does not have `schema_version: 1`, stop and ask for the app-server bootstrap to be run first.

## Step 1: Inventory the Diff and Write the Contract

Inspect the current branch against its default branch:

```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 diff "$DEFAULT_BRANCH"...HEAD --name-only
git log "$DEFAULT_BRANCH"..HEAD --oneline
```

Build a Diff Trigger Inventory with one row for every changed behavior that this container can exercise. Include UI routes, response fields, auth boundaries, negative paths, and downstream effects. Pure refactors, logs, static inspection, and container health are supporting evidence only.

The default contract for this repository is:

| # | Method | Path | Expected | What it proves |
| --- | --- | --- | --- | --- |
| 1 | GET | / | 200 | The public CRA app shell is reachable |
| 2 | GET | /manifest.json | 200 | The public static manifest is served |
| 3 | GET | /favicon.ico | 200 | The public static asset path is served |

Add branch-specific assertions for any changed route or behavior. The dev server uses SPA fallback, so do not claim a missing client route is a 404 unless the live response demonstrates that behavior. Do not use the default contract to cover changes under `server/`; those changes are not reachable through this recipe and must remain uncovered.

## Step 2: Start the App

Run the generated start-app-server skill and capture its container ID:

```text
Skill({"skill": "start-app-server"})
```

If the caller provides an environment artifact, reuse it only when its recorded `head_sha` matches the live branch and its health check still passes. Otherwise create an artifact at `/tmp/codepress-qa-verifier-runs/verify-env-<pr>-<sha>-<run>.json` containing the mode, 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 the backend. Report the startup failure and stop.

## Step 3: Authenticate

The selected frontend has no authentication gate. Skip login and use `useCookieJar: true` on the public requests.

## Step 4: Execute the Contract

Run every contract item in order:

```text
forward_app_request(
containerId=CONTAINER_ID,
path="/",
method="GET",
useCookieJar=true
)
```

Repeat with `/manifest.json` and `/favicon.ico`. Record the actual status, up to the first 500 characters of the response body, and a one-sentence proof note for each item. A failed item needs a diagnosis. Do not mark the overall run PASS unless every gap-worthy row in the Diff Trigger Inventory has a live result.

Before marking an item incomplete, make up to three materially different recovery attempts: check the exact path and method, inspect container logs, and retry after resolving any real startup or asset issue. Do not mock responses. If a changed behavior cannot be reached through this container, mark it as incomplete rather than silently omitting it.

## Step 5: UI Coverage

If the diff changes visible files under `web/src`, `web/public`, or `web/e2e`, use the repo's PR screenshot/Playwright setup for supporting visual evidence at `/`. A screenshot alone does not prove interactive behavior; add real browser assertions for changed interactions. If a future frontend-qa skill exists, run it for behavioral UI coverage. The overall verification cannot be PASS when a changed UI behavior is only captured visually and not behaviorally exercised.

## Step 6: Review Logs

Always inspect the container logs:

```text
get_app_server_logs(containerId=CONTAINER_ID, tail=500)
```

Record errors, critical messages, or 5xx traces that relate to the contract. A clean log review supports the HTTP results but cannot replace them.

## Step 7: Write the Report

Write `/tmp/local-verification-report.md`. The 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 — quantfive/django-react-intro

**PR Head SHA:** `<live head SHA, or local HEAD when no PR exists>`

<!-- codepress-verify-result: verdict=<PASS|FAIL> head=<same head SHA> -->

**Environment artifact:** `/tmp/codepress-qa-verifier-runs/verify-env-...`

### Diff Trigger Inventory

| Surface | Location | Contract item |
| --- | --- | --- |
| <changed behavior> | <file or route> | #1 |

### Verification Contract Results

| # | Assertion | Result | Details |
| --- | --- | --- | --- |
| 1 | GET / → 200 | ✅ PASS | <actual status and response excerpt> |

### Log Review

- <findings, or no errors in container logs>

### Container

- ID: <CONTAINER_ID>
- Stopped: yes / no

### Overall: ✅ PASS
```

Use `❌ FAIL` whenever an assertion fails or a changed behavior is not covered. The report must include a current-head `codepress-verify-result` marker when a PR exists.

## Step 8: Post the Report

When an open PR exists, post the exact report file with the `post_pr_comment` tool. If no PR exists, keep the report at the path above and include it in the session handoff. Post failures too; they are actionable evidence.

## Step 9: Cleanup

If no open PR needs the environment for a follow-up judge, stop the container:

```text
stop_app_server(containerId=CONTAINER_ID)
```

Do not leave a container running after a standalone local verification unless the caller explicitly asks to keep it.

## Known Issues at Bootstrap Time

- The recipe verifies only the CRA frontend. The Django backend and its `/api/auth/` routes are not connected to the selected web server.
- The frontend is a starter app with SPA fallback; unknown client-side routes may return the home HTML with status 200.
24 changes: 24 additions & 0 deletions .codepress/start-app-server/recipe.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"schema_version": 1,
"bootstrapped_at": "2026-08-10T04:15:25Z",
"origin": "bootstrap",
"repair_count": 0,
"dockerfile_path": "Dockerfile",
"port": 3000,
"validation_status_codes": [
200,
301,
302,
404
],
"input_checksums": {
"dockerfile": "f62f4ad864b4fcbe",
"dependency_manifest": "3e3a3c381db1ac9e"
},
"system_packages": [],
"known_fixes": [
"Created a standalone root Dockerfile because .codepress/dev-server/Dockerfile.web expects a bind-mounted checkout.",
"Pinned @playwright/test to 1.53.2 because current releases require Node 20 while the CRA image uses Node 18."
],
"discovery_notes": "This repository contains a Create React App frontend under web/ and a Django backend under server/. The frontend is the self-contained HTTP surface chosen for this single app-server recipe because it has a working start command and the current UI does not call the Django server."
}
Loading