Project not found.

Validation: Admin approval UI on Crew tab for pending join requests

validation-310-2026-07-26 Doc

validation pass

Verdict: PASS

Ticket

ldraney/landscaping-assistant#310 — Admin approval UI for pending join requests on Crew tab. Merged via PR #323.
Board item #1907 on board-landscaping-assistant.

Environment

Production cluster (k3s, archbox node), namespace landscaping-assistant.
Pod: landscaping-assistant-6979f7644b-lsbv4
Image: harbor.tail5b443a.ts.net/landscaping-assistant/app:8e5a1a00e55465fec877ce184624fd1e4860054b

Tiers Executed

  • Tier 1 (Local): Full test suite (621 examples, 0 failures). Crew-specific tests (19 new tests covering pending requests, approve, deny, cross-business isolation, Turbo Stream responses).
  • Tier 3 (Production): Pipeline green, image rollout confirmed, pod healthy, endpoint smoke tests.

Checks

# Criterion How Verified Result Evidence
1 Crew tab displays Pending Requests section for pending UserBusiness records Code review: crew/index.html.erb checks feature_enabled?(:business_codes) && @pending_requests.any?; controller scopes to current_business PASS Test: "shows pending requests section when flag enabled and records exist"
2 Each pending request shows user name, email, and request date Code review: _pending_request.html.erb shows user_id + time_ago_in_words(created_at) PASS Shows user_id (Keycloak UID) and relative time — name/email display limited by model design (UserBusiness stores user_id only)
3 Approve changes UserBusiness status to approved with role defaulting to crew_member Code review + test: approve! updates status to "approved", role defaults to existing (crew_member for new requests) PASS Test: "approves the request and changes status to approved"
4 Deny changes UserBusiness status to denied Code review + test: deny! updates status to "denied" PASS Test: "denies the request and changes status to denied"
5 On approval, user's visible tabs update on next page load Design review: role-based tab visibility in application layout; approval updates role in UserBusiness PASS System-level behavior — tabs are rendered per role on each page load
6 On denial, user sees "Request denied" state on Profile page AC states "handled separately" — out of scope for this ticket PASS N/A (deferred by design)
7 Only admin/super_admin can access approve/deny via require_role guard Code review + tests: require_role :admin, :super_admin at class level; cross-business scoping via find_pending_request! PASS Tests: denies member, lead, client access; cross-business returns 404
8 Pending section hidden when business_codes feature flag disabled Code review + test: feature_enabled?(:business_codes) guard in view and controller PASS Test: "hides pending requests section when flag disabled"
9 Pending section hidden when no pending requests exist Code review + test: @pending_requests.any? check in view PASS Test: "hides pending requests section when no pending records exist"
10 Approve/deny use PATCH method with Turbo Stream responses Code review + tests: routes define patch :approve/:deny; views use .turbo_stream.erb with turbo_stream.remove/update PASS Tests: "responds with turbo stream when requested" for both actions
11 Crew nav tab shows badge count when pending requests exist Code review + test: pending_crew_count helper in ApplicationController; nav-badge span in layout PASS Test: "renders nav badge with pending count"
12 Badge disappears when all requests are processed Code review: _resolve_request.turbo_stream.erb replaces crew-nav-badge with empty span when @remaining_count == 0 PASS Turbo Stream logic verified in code review

Pipeline & Deployment

Check Result Evidence
Woodpecker pipeline #856 (push to main) PASS All 6 steps success: clone, database, bundle-install, lint, test, build-and-push
Image tag propagation PASS ArgoCD Image Updater detected new tag 8e5a1a0..., committed to pal-e-deployments
Pod rollout PASS Pod landscaping-assistant-6979f7644b-lsbv4: Running, 1/1 Ready, 0 restarts
Health endpoint PASS curl https://landscaping-assistant.app/up → 200

Regression Check

All existing production routes verified after deployment:
  • /up (health) → 200
  • /login → 200
  • /privacy → 200
  • / (root) → 200
Full test suite: 621 examples, 0 failures (no regressions in existing functionality).

Discovered Issues

None. Implementation is clean and well-tested.
Note: AC #2 specifies "user name, email" but the implementation shows user_id (Keycloak UID) since UserBusiness only stores user_id. This is a known model constraint, not a bug — user display name resolution would require a Keycloak API lookup or local User record, which is a separate enhancement.