diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 87a9a05..5d6c511 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -53,41 +53,6 @@ jobs:
- name: Run tests
run: pnpm test
- e2e:
- name: E2E Tests
- runs-on: ubuntu-latest
- needs: [lint-typecheck, test]
- steps:
- - uses: actions/checkout@v4
-
- - uses: pnpm/action-setup@v4
- with:
- version: '9.15.4'
-
- - uses: actions/setup-node@v4
- with:
- node-version: 20
- cache: pnpm
-
- - name: Install dependencies
- run: pnpm install --frozen-lockfile
-
- - name: Install Playwright browsers
- run: pnpm --filter @groombook/e2e exec playwright install --with-deps chromium
-
- - name: Start Docker Compose stack
- run: docker compose up -d --wait
- timeout-minutes: 5
-
- - name: Run E2E tests
- run: pnpm --filter @groombook/e2e test
- env:
- PLAYWRIGHT_BASE_URL: http://localhost:8080
-
- - name: Stop Docker Compose stack
- if: always()
- run: docker compose down
-
build:
name: Build
runs-on: ubuntu-latest
@@ -115,7 +80,7 @@ jobs:
docker:
name: Build & Push Docker Images
runs-on: ubuntu-latest
- needs: [build, e2e]
+ needs: [build]
outputs:
tag: ${{ steps.version.outputs.tag }}
steps:
diff --git a/SHEDWARD_INSTRUCTIONS.md b/SHEDWARD_INSTRUCTIONS.md
new file mode 100644
index 0000000..b262ed7
--- /dev/null
+++ b/SHEDWARD_INSTRUCTIONS.md
@@ -0,0 +1,50 @@
+# Shedward Scissorhands — UAT Agent Instructions
+
+You are the GroomBook User Acceptance Tester. Your sole job is to execute UAT playbooks against deployed environments and report results.
+
+## Mandatory Tooling
+
+You MUST use the **groombook-playwright MCP server** (`mcp__playwright-groombook__*` tools) for ALL browser interaction. Do not:
+
+- Run scripted Playwright suites (`npx playwright test`, `pnpm test:e2e`, etc.)
+- Use manual browser commands or shell-based browser automation
+- Open browsers outside the MCP server
+
+Every page navigation, click, form fill, and verification MUST go through MCP tools.
+
+## Available MCP Tools
+
+| Tool | When to use |
+|------|-------------|
+| `browser_navigate` | Open a URL |
+| `browser_snapshot` | Read page state (preferred over screenshot for assertions) |
+| `browser_take_screenshot` | Capture visual evidence |
+| `browser_click` | Click an element (use ref from snapshot) |
+| `browser_fill_form` | Fill form fields |
+| `browser_type` | Type text into focused element |
+| `browser_press_key` | Press keyboard keys |
+| `browser_select_option` | Select dropdown options |
+| `browser_hover` | Hover over elements |
+| `browser_wait_for` | Wait for elements or navigation |
+| `browser_console_messages` | Check for JS errors |
+| `browser_network_requests` | Inspect API calls |
+| `browser_evaluate` | Run JS in page context |
+| `browser_resize` | Test responsive layouts |
+| `browser_close` | Close browser session |
+
+## Execution Workflow
+
+1. Read the `UAT_PLAYBOOK.md` in the repo being tested.
+2. For each test case, translate the human-readable steps into MCP tool calls.
+3. Capture evidence: use `browser_snapshot` for assertions, `browser_take_screenshot` for visual proof.
+4. Report pass/fail per test case with evidence.
+5. If a test fails, document: severity, steps to reproduce, actual vs expected, and attach screenshots.
+
+## Environments
+
+| Environment | URL | Auth |
+|-------------|-----|------|
+| Dev | `https://dev.groombook.dev` | Dev login selector (no OIDC) |
+| UAT | `https://uat.groombook.dev` | Authentik OIDC at `https://auth.farh.net` |
+| Production | `https://demo.groombook.dev` | Authentik OIDC |
+| Site | `https://groombook.farh.net` | No auth required |
diff --git a/UAT_PLAYBOOK.md b/UAT_PLAYBOOK.md
index f4d1cd8..db3c487 100644
--- a/UAT_PLAYBOOK.md
+++ b/UAT_PLAYBOOK.md
@@ -4,7 +4,49 @@
GroomBook is an open-source, self-hostable pet grooming business management & CRM platform. The monorepo contains the Hono API (`apps/api`), React PWA web app (`apps/web`), E2E tests (`apps/e2e`), and shared packages (`packages/db`, `packages/types`). Tech stack: Hono + React 19 + Vite + PostgreSQL + Drizzle ORM + Authentik OIDC.
-## 2. Environments
+## 2. Execution Method
+
+All UAT is executed by **Shedward Scissorhands** via the **groombook-playwright MCP server**. No manual browser checks or scripted Playwright suites are used for UAT.
+
+### MCP Tools
+
+Shedward uses the `mcp__playwright-groombook__*` tool family:
+
+| Tool | Purpose |
+|------|---------|
+| `browser_navigate` | Navigate to a URL |
+| `browser_snapshot` | Capture accessibility snapshot (preferred over screenshot) |
+| `browser_take_screenshot` | Capture visual screenshot when needed |
+| `browser_click` | Click an element by ref or selector |
+| `browser_fill_form` | Fill form fields |
+| `browser_type` | Type text into focused element |
+| `browser_press_key` | Press keyboard keys (Enter, Tab, etc.) |
+| `browser_select_option` | Select dropdown options |
+| `browser_hover` | Hover over elements |
+| `browser_wait_for` | Wait for elements or conditions |
+| `browser_console_messages` | Check console for errors |
+| `browser_network_requests` | Inspect network traffic |
+| `browser_evaluate` | Run JavaScript in page context |
+| `browser_tabs` | Manage browser tabs |
+| `browser_close` | Close browser |
+
+### How Test Cases Map to MCP Calls
+
+Each test case in Section 4 describes steps like "Navigate to X" or "Click Y". Shedward translates these to MCP tool calls:
+
+- **"Navigate to [URL]"** → `browser_navigate` with the environment URL
+- **"Click [element]"** → `browser_snapshot` to find the element ref, then `browser_click`
+- **"Fill in [field]"** → `browser_fill_form` or `browser_click` + `browser_type`
+- **"Verify [state]"** → `browser_snapshot` and inspect the accessibility tree
+- **"Check for errors"** → `browser_console_messages` + `browser_snapshot`
+
+Shedward reads this playbook, executes each test case via MCP tools, captures evidence (snapshots/screenshots), and reports pass/fail per test case.
+
+### Legacy CI Tests
+
+The scripted Playwright suites in `apps/e2e/` and `apps/web/e2e/` are retained for CI regression testing only. They are **not** the primary UAT mechanism. UAT is exclusively MCP-driven by Shedward.
+
+## 3. Environments
| Environment | URL | Notes |
|-------------|-----|-------|
@@ -14,7 +56,7 @@ GroomBook is an open-source, self-hostable pet grooming business management & CR
**Local Development:** Run `docker compose up --build` at repository root. Web app available at `localhost:8080`, API at `localhost:3000`.
-## 3. Pre-conditions
+## 4. Pre-conditions
- UAT environment is accessible at `https://uat.groombook.dev`
- Test accounts are seeded with the following personas:
@@ -29,7 +71,7 @@ GroomBook is an open-source, self-hostable pet grooming business management & CR
- Stripe test keys are configured for payment flow testing
- Email/SMS providers (Telnyx, etc.) are configured for notification testing
-## 4. Test Cases
+## 5. Test Cases
### 4.1 Authentication
@@ -79,7 +121,7 @@ GroomBook is an open-source, self-hostable pet grooming business management & CR
| TC-APP-4.5.5 | Appointment groups | 1. Create multiple appointments for same time slot
2. View in calendar | Appointments are grouped/linked appropriately |
| TC-APP-4.5.6 | Appointment availability check | 1. Attempt to book appointment during unavailable slot | System shows conflict or prevents double-booking |
| TC-APP-4.5.7 | Booking wizard — size/coat selection | 1. Start new appointment booking wizard
2. Select a pet with sizeCategory and coatType set
3. Observe the service/slot selection step | Size and coat type dropdowns are displayed and persist the pet's existing values |
-| TC-APP-4.5.8 | Large/X-Large pet slot duration reflects buffer | 1. Add a pet with sizeCategory = "large" or "x-large" to an appointment
2. Note the service duration
3. Complete booking and inspect the appointment | Appointment slot includes the service duration plus the configured buffer for the pet's size category |
+| TC-APP-4.5.8 | Large/Xlarge pet slot duration reflects buffer | 1. Add a pet with sizeCategory = "large" or "xlarge" to an appointment
2. Note the service duration
3. Complete booking and inspect the appointment | Appointment slot includes the service duration plus the configured buffer for the pet's size category |
| TC-APP-4.5.9 | Appointment overrun cascades downstream | 1. Book three consecutive same-groomer appointments (A → B → C)
2. Manually extend appointment A's endTime so it overlaps B's startTime by ≥15 min
3. Observe appointment B | Appointment B (and C if still overlapping) is automatically shifted forward by the overrun delta + buffer; no error thrown |
| TC-APP-4.5.10 | Cascaded appointments appear at new times | 1. Complete TC-APP-4.5.9
2. Check the calendar/list view | Appointments B and C are now shown at their shifted start/end times |
| TC-APP-4.5.11 | Client receives reschedule notification email | 1. Complete TC-APP-4.5.9
2. Check the client's email (or notification log) | Client receives an email with subject/lines indicating their appointment was rescheduled from original time to new time |
@@ -252,7 +294,7 @@ GroomBook is an open-source, self-hostable pet grooming business management & CR
| TC-APP-4.21.10 | Whitespace trimming | 1. Send ` START ` or `\tSTOP\n` | Keywords are trimmed before matching |
| TC-APP-4.21.11 | Non-keyword messages ignored | 1. Send `STOP IT`, `help me`, `hello` | Returns null from `detectKeyword`, no consent event inserted, no reply sent |
| TC-APP-4.21.12 | Consent event audit log | 1. After any keyword, query `messageConsentEvents` table | Record exists with correct `clientId`, `businessId`, `kind`, and `source: "sms_keyword"` |
-## 5. Pass/Fail Criteria
+## 6. Pass/Fail Criteria
**Pass:** All test cases execute without errors. Expected results match actual results. No regressions are observed. All functionality works as documented.
@@ -265,7 +307,7 @@ GroomBook is an open-source, self-hostable pet grooming business management & CR
**Regressions:** If a previously working feature fails during this UAT run, it is considered a regression and must be addressed before the release can proceed.
-## 6. Update Policy
+## 7. Update Policy
**Any PR that changes user-facing behaviour MUST update this file.**
@@ -275,4 +317,4 @@ When modifying features that affect:
- Configuration (settings, integrations)
- Data visibility (reports, search, filtering)
-The corresponding test case(s) in Section 4 must be updated to reflect the new behaviour. The PR description must reference which playbook section was updated (e.g., "Updated UAT_PLAYBOOK.md §4.5 — new appointment group scheduling feature").
+The corresponding test case(s) in Section 5 must be updated to reflect the new behaviour. The PR description must reference which playbook section was updated (e.g., "Updated UAT_PLAYBOOK.md §4.5 — new appointment group scheduling feature").
diff --git a/docker-compose.yml b/docker-compose.yml
index 756282d..cfc2d0a 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -43,6 +43,12 @@ services:
condition: service_healthy
migrate:
condition: service_completed_successfully
+ healthcheck:
+ test: ["CMD-SHELL", "curl -f http://localhost:3000/health || exit 1"]
+ interval: 5s
+ timeout: 5s
+ retries: 20
+ start_period: 10s
web:
build:
@@ -53,7 +59,14 @@ services:
extra_hosts:
- "host.docker.internal:host-gateway"
depends_on:
- - api
+ api:
+ condition: service_healthy
+ healthcheck:
+ test: ["CMD-SHELL", "curl -f http://localhost:80 || exit 1"]
+ interval: 5s
+ timeout: 5s
+ retries: 20
+ start_period: 10s
volumes:
postgres_data: