Skip to content

Panel P5.3.2: Playwright e2e for the check-in scan→verdict flow - #98

Merged
thevladbog merged 18 commits into
mainfrom
panel/p5.3.2-e2e-checkin
Jul 21, 2026
Merged

Panel P5.3.2: Playwright e2e for the check-in scan→verdict flow#98
thevladbog merged 18 commits into
mainfrom
panel/p5.3.2-e2e-checkin

Conversation

@thevladbog

@thevladbog thevladbog commented Jul 21, 2026

Copy link
Copy Markdown
Owner

Panel P5.3.2 — Playwright e2e for the check-in scan→verdict flow

Second of five P5.3 sub-cycles. Ships the first Playwright e2e suite for panel/ — none existed before (only an unrelated, CI-unwired local harness in landing/). Covers the check-in station's scan→verdict flow against a real backend + Postgres, no mocks.

Spec: docs/superpowers/specs/2026-07-21-panel-p5.3.2-e2e-checkin-design.md · Plan: docs/superpowers/plans/2026-07-21-panel-p5.3.2-e2e-checkin.md (amended mid-execution — see below)

What changed

  • panel/e2e/ — a self-contained seed helper (fixtures/seedCheckinEvent.ts) drives the real backend API (login, create event, attendee, badge template, staff, checkin-settings with printing off, station) to reach readiness.ready === true, then checkin.spec.ts injects the JWT into localStorage (bypassing the login UI — the route guard only checks token presence) and drives the real station UI. One test covers all three reachable verdicts from one setup: checked_inalready_checked_innot_found.
  • Tooling@playwright/test (chromium only, matching landing/'s precedent), panel/playwright.config.ts (locale pinned to en-US to avoid host-OS-locale-dependent selector flakiness).
  • panel/vitest.config.ts — excludes e2e/** from Vitest's own discovery (its default glob matches *.spec.ts too — without this, the CI-blocking test-panel job would break the moment the e2e spec existed).
  • CI — new e2e-panel job (dev-mode: real Postgres + go run backend + panel dev server), deliberately soft/non-blocking (not in ci-success's needs:) until proven stable over real PRs.
  • Fixed a wrong printed test password in scripts/seed.sh, scripts/start-all.sh, .github/SECURITY.md (said password123; the real bcrypt-verified plaintext is password).

A real production bug, found and fixed along the way

Standing up a live stack to seed the e2e event surfaced that POST /api/events/{event_id}/staff has always 500'd in every real deployment — migration 000002's CREATE TABLE IF NOT EXISTS event_staff (id, ..., assigned_by, ...) silently no-op'd because the table already existed (created narrower by migration 000001), so the live schema never gained the columns AssignStaffToEvent's INSERT writes to. Fixed with a new migration (000025, schema-only, no Go changes) — user-approved as an inline task in this cycle. Proven end-to-end with a real 201 response before and after.

Verification

Final whole-branch review (Opus) caught 1 Critical: the new CI job would have failed on a genuinely fresh database (backend's onprem-mode bootstrap requires IDENTO_ADMIN_EMAIL/IDENTO_ADMIN_PASSWORD on an empty DB, which the job didn't set) — the local sweep had passed only because the local dev Postgres had leftover state from earlier testing, masking it. Fixed, then empirically verified: destroyed the local DB volume, recreated it genuinely empty, and re-ran the full suite end to end against a from-scratch-bootstrapped backend — passed. Everything else (the event_staff fix's safety, seed helper API contracts, readiness math, auth bypass, selectors, soft-gating) was independently verified sound with zero other findings.

Deferred

blocked (zone-rule) verdict coverage, print/agent-integration coverage, cross-browser coverage. Promoting e2e-panel from soft to required once proven stable over real PRs. P5.3.3 (WCAG-AA a11y audit) follows.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added end-to-end test coverage for the panel check-in scan flow, including successful scans, repeated scans, and unknown badge handling.
    • Added automated test setup and scenario seeding for check-in verdict verification.
  • Bug Fixes
    • Fixed event staff data so staff assignment works correctly for event check-in.
  • Documentation
    • Updated displayed development/test credentials to match the current seeded password.
  • Tests
    • Added a non-blocking CI “soft check” that runs the panel end-to-end suite and uploads the Playwright report.

CI Bot added 15 commits July 21, 2026 05:53
The seeded admin@test.com account's real bcrypt-verified password is
"password" (matches backend/migrations/seed.sql's own comment), but
scripts/seed.sh, scripts/start-all.sh, and .github/SECURITY.md all
printed/documented "password123" as the hint. Corrected all three.

Also wires a new e2e-panel CI job (Playwright, backend+Postgres up,
npm run e2e -w panel) after docker-build-image. It's a soft check —
deliberately excluded from ci-success's needs: until proven stable.
Copilot AI review requested due to automatic review settings July 21, 2026 07:08

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@github-actions github-actions Bot added documentation Improvements or additions to documentation backend ci panel labels Jul 21, 2026
@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 5e5b7432-d789-40ab-83e5-524d3aef0602

📥 Commits

Reviewing files that changed from the base of the PR and between c1a6c5e and b089028.

📒 Files selected for processing (3)
  • .github/workflows/ci.yml
  • .gitignore
  • .superpowers/sdd/progress.md
🚧 Files skipped from review as they are similar to previous changes (2)
  • .github/workflows/ci.yml
  • .superpowers/sdd/progress.md

📝 Walkthrough

Walkthrough

Adds Playwright coverage for the panel check-in scan-to-verdict flow, repairs missing event_staff columns, configures a non-blocking CI job, excludes E2E specs from Vitest, and aligns displayed development credentials.

Changes

Panel check-in E2E

Layer / File(s) Summary
Event staff schema repair
backend/migrations/*, docs/superpowers/plans/...
Adds reversible migrations for event_staff.id and event_staff.assigned_by.
Playwright check-in flow
panel/e2e/*, panel/playwright.config.ts, panel/package.json, panel/vitest.config.ts, docs/superpowers/specs/*
Seeds a real backend event, injects authentication, and verifies allowed, already-checked-in, and unknown-code verdicts.
CI execution and credential alignment
.github/workflows/ci.yml, scripts/*, .github/SECURITY.md, .superpowers/sdd/progress.md, .gitignore
Adds a conditional soft E2E job, updates displayed credentials to password, ignores Playwright artifacts, and records verification details.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Playwright
  participant BackendAPI
  participant Postgres
  participant Panel
  Playwright->>BackendAPI: Seed event and check-in fixtures
  BackendAPI->>Postgres: Store seeded data
  Playwright->>Panel: Inject JWT and open station page
  Panel->>BackendAPI: Submit badge scan
  BackendAPI-->>Panel: Return verdict
  Panel-->>Playwright: Render verdict card
Loading

Possibly related PRs

  • thevladbog/idento#77: Implements the check-in loop and verdict behavior exercised by the new Playwright test.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: adding Playwright e2e coverage for the panel check-in scan-to-verdict flow.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch panel/p5.3.2-e2e-checkin

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
backend/migrations/000025_fix_event_staff_columns.up.sql (1)

14-16: 🩺 Stability & Availability | 🔵 Trivial

Consider the locking impact of adding columns with defaults and foreign keys.

Adding a DEFAULT with a volatile function like gen_random_uuid() requires a table rewrite and an ACCESS EXCLUSIVE lock, which blocks all reads and writes. Additionally, adding a foreign key constraint requires a table scan and a SHARE ROW EXCLUSIVE lock on both tables.

If event_staff is large in production, consider breaking this into safer, non-blocking steps:

  1. Add the id column as nullable.
  2. Backfill the IDs in batches.
  3. Set the column to NOT NULL and add the default.
  4. Add the foreign key constraint with NOT VALID, then run VALIDATE CONSTRAINT in a separate transaction.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/migrations/000025_fix_event_staff_columns.up.sql` around lines 14 -
16, Refactor the event_staff migration to avoid a table rewrite and long
blocking locks: add id as nullable without a default, backfill UUIDs in batches,
then enforce NOT NULL and add the gen_random_uuid() default. Add the assigned_by
foreign key as NOT VALID and validate it separately, preserving the existing
users(id) relationship.

Source: Linters/SAST tools

.github/workflows/ci.yml (1)

216-216: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Disable credential persistence on checkout for this job.

This job runs several supply-chain-exposed commands (npm ci, npx playwright install --with-deps, go run main.go) with the ephemeral GITHUB_TOKEN still persisted in git config for the whole job. Impact is bounded by the job's already-minimal contents: read permission, but explicitly dropping it is a one-line hardening step with no downside.

🔒 Proposed fix
       - uses: actions/checkout@v5
+        with:
+          persist-credentials: false
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/ci.yml at line 216, Update the actions/checkout@v5 step to
disable credential persistence by configuring persist-credentials as false,
ensuring the ephemeral GITHUB_TOKEN is not retained in git configuration for the
remainder of the job.

Source: Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In @.github/workflows/ci.yml:
- Line 216: Update the actions/checkout@v5 step to disable credential
persistence by configuring persist-credentials as false, ensuring the ephemeral
GITHUB_TOKEN is not retained in git configuration for the remainder of the job.

In `@backend/migrations/000025_fix_event_staff_columns.up.sql`:
- Around line 14-16: Refactor the event_staff migration to avoid a table rewrite
and long blocking locks: add id as nullable without a default, backfill UUIDs in
batches, then enforce NOT NULL and add the gen_random_uuid() default. Add the
assigned_by foreign key as NOT VALID and validate it separately, preserving the
existing users(id) relationship.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: f114e740-9f2a-484f-a9e0-e9c0f302509f

📥 Commits

Reviewing files that changed from the base of the PR and between 191d270 and c1a6c5e.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (14)
  • .github/SECURITY.md
  • .github/workflows/ci.yml
  • .superpowers/sdd/progress.md
  • backend/migrations/000025_fix_event_staff_columns.down.sql
  • backend/migrations/000025_fix_event_staff_columns.up.sql
  • docs/superpowers/plans/2026-07-21-panel-p5.3.2-e2e-checkin.md
  • docs/superpowers/specs/2026-07-21-panel-p5.3.2-e2e-checkin-design.md
  • panel/e2e/checkin.spec.ts
  • panel/e2e/fixtures/seedCheckinEvent.ts
  • panel/package.json
  • panel/playwright.config.ts
  • panel/vitest.config.ts
  • scripts/seed.sh
  • scripts/start-all.sh

@thevladbog

Copy link
Copy Markdown
Owner Author

Thanks for the review — both nitpicks addressed:

.github/workflows/ci.yml (persist-credentials) — fixed in a1bf790. Good catch, no downside to dropping it.

backend/migrations/000025_fix_event_staff_columns.up.sql (locking impact) — the general advice (nullable→backfill→NOT NULL→NOT VALID FK→VALIDATE separately) is correct practice for a large, populated table, but doesn't apply here: event_staff is provably empty in every real deployment. The only INSERT path (AssignStaffToEvent, pg_store.go) has unconditionally errored since migration 000002 silently no-op'd (confirmed during review — CREATE TABLE IF NOT EXISTS skips the whole statement when the table already exists, which it did from 000001's narrower definition; Postgres never reconciles columns). So no row has ever survived a real INSERT INTO event_staff — the ACCESS EXCLUSIVE rewrite this migration takes is against zero rows, effectively instant. Keeping the single-statement ALTER TABLE for simplicity; the staged approach would be the right call if this table could plausibly hold real data, which it structurally cannot until this migration itself ships.

@thevladbog

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@thevladbog

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@thevladbog
thevladbog merged commit e64041e into main Jul 21, 2026
34 checks passed
@thevladbog
thevladbog deleted the panel/p5.3.2-e2e-checkin branch July 21, 2026 08:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backend ci documentation Improvements or additions to documentation panel

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants